diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fb6b36e1a09da..21695339f06b4 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1399,6 +1399,7 @@ impl Expr {
             // Never need parens
             ExprKind::Array(_)
             | ExprKind::Await(..)
+            | ExprKind::Use(..)
             | ExprKind::Block(..)
             | ExprKind::Call(..)
             | ExprKind::ConstBlock(_)
@@ -1588,6 +1589,8 @@ pub enum ExprKind {
     Gen(CaptureBy, P<Block>, GenBlockKind, Span),
     /// An await expression (`my_future.await`). Span is of await keyword.
     Await(P<Expr>, Span),
+    /// A use expression (`x.use`). Span is of use keyword.
+    Use(P<Expr>, Span),
 
     /// A try block (`try { ... }`).
     TryBlock(P<Block>),
@@ -1757,8 +1760,17 @@ pub enum CaptureBy {
         /// The span of the `move` keyword.
         move_kw: Span,
     },
-    /// `move` keyword was not specified.
+    /// `move` or `use` keywords were not specified.
     Ref,
+    /// `use |x| y + x`.
+    ///
+    /// Note that if you have a regular closure like `|| x.use`, this will *not* result
+    /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type
+    /// of `x` and treat `x.use` as either a copy/clone/move as appropriate.
+    Use {
+        /// The span of the `use` keyword.
+        use_kw: Span,
+    },
 }
 
 /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index f14646b5a99a5..ee894db7b966b 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1745,6 +1745,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             vis.visit_expr(expr);
             vis.visit_span(await_kw_span);
         }
+        ExprKind::Use(expr, use_kw_span) => {
+            vis.visit_expr(expr);
+            vis.visit_span(use_kw_span);
+        }
         ExprKind::Assign(el, er, span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
@@ -1895,6 +1899,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
         CaptureBy::Value { move_kw } => {
             vis.visit_span(move_kw);
         }
+        CaptureBy::Use { use_kw } => {
+            vis.visit_span(use_kw);
+        }
     }
 }
 
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 64f2a98b8a6fc..e43d78f6e7217 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
             Assign(e, _, _)
             | AssignOp(_, e, _)
             | Await(e, _)
+            | Use(e, _)
             | Binary(_, e, _)
             | Call(e, _)
             | Cast(e, _)
@@ -224,6 +225,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
             | Lit(_)
             | Type(_, _)
             | Await(_, _)
+            | Use(_, _)
             | Field(_, _)
             | Index(_, _, _)
             | Underscore
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 37139e664f3d2..43ffbe9b071d6 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1211,6 +1211,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         }
         ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)),
         ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)),
+        ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)),
         ExprKind::Assign(lhs, rhs, _span) => {
             try_visit!(visitor.visit_expr(lhs));
             try_visit!(visitor.visit_expr(rhs));
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9c3db7abc1ccc..871c69c9eb136 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -207,6 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     },
                 ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
+                ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),
                 ExprKind::Closure(box Closure {
                     binder,
                     capture_clause,
@@ -1067,6 +1068,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         )
     }
 
+    fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+        hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
+    }
+
     fn lower_expr_closure(
         &mut self,
         binder: &ClosureBinder,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index de11fe770c5b3..31ff102c127a3 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -489,6 +489,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(dyn_star, "`dyn*` trait objects are experimental");
     gate_all!(const_closures, "const closures are experimental");
     gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
+    gate_all!(ergonomic_clones, "ergonomic clones are experimental");
     gate_all!(explicit_tail_calls, "`become` expression is experimental");
     gate_all!(generic_const_items, "generic const items are experimental");
     gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 496323a35b8d9..e3c41f117abb8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -574,6 +574,14 @@ impl<'a> State<'a> {
                 );
                 self.word(".await");
             }
+            ast::ExprKind::Use(expr, _) => {
+                self.print_expr_cond_paren(
+                    expr,
+                    expr.precedence() < ExprPrecedence::Unambiguous,
+                    fixup,
+                );
+                self.word(".use");
+            }
             ast::ExprKind::Assign(lhs, rhs, _) => {
                 self.print_expr_cond_paren(
                     lhs,
@@ -885,6 +893,7 @@ impl<'a> State<'a> {
     fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
         match capture_clause {
             ast::CaptureBy::Value { .. } => self.word_space("move"),
+            ast::CaptureBy::Use { .. } => self.word_space("use"),
             ast::CaptureBy::Ref => {}
         }
     }
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 30e94b0bec708..c9be5575da5ce 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 .expect_closure();
             let span = match capture_clause {
                 rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
+                rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(),
                 rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
             };
             diag.span_suggestion_verbose(
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index be4a7736b1c20..145137f923691 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                             ) => {
                                 capture_reason = format!("mutable borrow of `{upvar}`");
                             }
-                            ty::UpvarCapture::ByValue => {
+                            ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
                                 capture_reason = format!("possible mutation of `{upvar}`");
                             }
                             _ => bug!("upvar `{upvar}` borrowed, but not mutably"),
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 68e0ab0933e61..64a533e05ffd4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1490,14 +1490,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                         let stmt = &bbd.statements[loc.statement_index];
                         debug!("temporary assigned in: stmt={:?}", stmt);
 
-                        if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind
-                        {
-                            propagate_closure_used_mut_place(self, source);
-                        } else {
-                            bug!(
-                                "closures should only capture user variables \
+                        match stmt.kind {
+                            StatementKind::Assign(box (
+                                _,
+                                Rvalue::Ref(_, _, source)
+                                | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
+                            )) => {
+                                propagate_closure_used_mut_place(self, source);
+                            }
+                            _ => {
+                                bug!(
+                                    "closures should only capture user variables \
                                  or references to user variables"
-                            );
+                                );
+                            }
                         }
                     }
                     _ => propagate_closure_used_mut_place(self, place),
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index bb9dc651cec25..a949ab94f3ad7 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Gen(_, _, _, _)
             | ExprKind::Await(_, _)
+            | ExprKind::Use(_, _)
             | ExprKind::Block(_, _)
             | ExprKind::Break(_, _)
             | ExprKind::Closure(_)
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 841d308418566..48c608f8f171b 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -473,6 +473,8 @@ declare_features! (
     (unstable, doc_masked, "1.21.0", Some(44027)),
     /// Allows `dyn* Trait` objects.
     (incomplete, dyn_star, "1.65.0", Some(102425)),
+    /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
+    (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 399f1f4b23730..7b927316f3b80 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2166,6 +2166,7 @@ impl Expr<'_> {
             | ExprKind::Tup(_)
             | ExprKind::Type(..)
             | ExprKind::UnsafeBinderCast(..)
+            | ExprKind::Use(..)
             | ExprKind::Err(_) => ExprPrecedence::Unambiguous,
 
             ExprKind::DropTemps(expr, ..) => expr.precedence(),
@@ -2212,6 +2213,7 @@ impl Expr<'_> {
             ExprKind::Path(QPath::TypeRelative(..))
             | ExprKind::Call(..)
             | ExprKind::MethodCall(..)
+            | ExprKind::Use(..)
             | ExprKind::Struct(..)
             | ExprKind::Tup(..)
             | ExprKind::If(..)
@@ -2285,7 +2287,9 @@ impl Expr<'_> {
 
     pub fn can_have_side_effects(&self) -> bool {
         match self.peel_drop_temps().kind {
-            ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false,
+            ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => {
+                false
+            }
             ExprKind::Type(base, _)
             | ExprKind::Unary(_, base)
             | ExprKind::Field(base, _)
@@ -2547,6 +2551,8 @@ pub enum ExprKind<'hir> {
     ///
     /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
     MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
+    /// An use expression (e.g., `var.use`).
+    Use(&'hir Expr<'hir>, Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
     /// A binary operation (e.g., `a + b`, `a * b`).
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index e349e23f7dcf5..6b34c2ac2ef46 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -821,6 +821,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             try_visit!(visitor.visit_expr(receiver));
             walk_list!(visitor, visit_expr, arguments);
         }
+        ExprKind::Use(expr, _) => {
+            try_visit!(visitor.visit_expr(expr));
+        }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
             try_visit!(visitor.visit_expr(left_expression));
             try_visit!(visitor.visit_expr(right_expression));
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index f5626937ec456..2c73ea6a11a76 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -171,6 +171,7 @@ language_item_table! {
     Copy,                    sym::copy,                copy_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     Clone,                   sym::clone,               clone_trait,                Target::Trait,          GenericRequirement::None;
     CloneFn,                 sym::clone_fn,            clone_fn,                   Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    UseCloned,               sym::use_cloned,          use_cloned_trait,           Target::Trait,          GenericRequirement::None;
     Sync,                    sym::sync,                sync_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     DiscriminantKind,        sym::discriminant_kind,   discriminant_kind_trait,    Target::Trait,          GenericRequirement::None;
     /// The associated item of the `DiscriminantKind` trait.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1658c8dac6768..b04d3256f7bea 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1544,6 +1544,10 @@ impl<'a> State<'a> {
             hir::ExprKind::MethodCall(segment, receiver, args, _) => {
                 self.print_expr_method_call(segment, receiver, args);
             }
+            hir::ExprKind::Use(expr, _) => {
+                self.print_expr(expr);
+                self.word(".use");
+            }
             hir::ExprKind::Binary(op, lhs, rhs) => {
                 self.print_expr_binary(op, lhs, rhs);
             }
@@ -2301,6 +2305,7 @@ impl<'a> State<'a> {
     fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
         match capture_clause {
             hir::CaptureBy::Value { .. } => self.word_space("move"),
+            hir::CaptureBy::Use { .. } => self.word_space("use"),
             hir::CaptureBy::Ref => {}
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index dec1779d92ca4..360d9a6cecd06 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -362,6 +362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Any expression child of these expressions constitute reads.
                     ExprKind::Array(_)
                     | ExprKind::Call(_, _)
+                    | ExprKind::Use(_, _)
                     | ExprKind::MethodCall(_, _, _, _)
                     | ExprKind::Tup(_)
                     | ExprKind::Binary(_, _, _)
@@ -552,6 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
             ExprKind::Block(body, _) => self.check_expr_block(body, expected),
             ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
+            ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected),
             ExprKind::MethodCall(segment, receiver, args, _) => {
                 self.check_expr_method_call(expr, segment, receiver, args, expected)
             }
@@ -1616,6 +1618,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
+    /// Checks use `x.use`.
+    fn check_expr_use(
+        &self,
+        used_expr: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        self.check_expr_with_expectation(used_expr, expected)
+    }
+
     fn check_expr_cast(
         &self,
         e: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index c0617119d67c7..9ff7eeb23688c 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -47,6 +47,21 @@ pub trait Delegate<'tcx> {
     /// the id of the binding in the pattern `pat`.
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
 
+    /// The value found at `place` is used, depending
+    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
+    ///
+    /// Use of a `Copy` type in a ByUse context is considered a use
+    /// by `ImmBorrow` and `borrow` is called instead. This is because
+    /// a shared borrow is the "minimum access" that would be needed
+    /// to perform a copy.
+    ///
+    ///
+    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
+    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
+    /// id will be the id of the expression `expr` but the place itself will have
+    /// the id of the binding in the pattern `pat`.
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
+
     /// The value found at `place` is being borrowed with kind `bk`.
     /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
     fn borrow(
@@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
         (**self).consume(place_with_id, diag_expr_id)
     }
 
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).use_cloned(place_with_id, diag_expr_id)
+    }
+
     fn borrow(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> {
 
     fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
+
     fn body_owner_def_id(&self) -> LocalDefId;
 
     fn tcx(&self) -> TyCtxt<'tcx>;
@@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
         self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
     }
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
+    }
+
     fn body_owner_def_id(&self) -> LocalDefId {
         self.body_id
     }
@@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
         self.0.type_is_copy_modulo_regions(ty)
     }
 
+    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.0.type_is_use_cloned_modulo_regions(ty)
+    }
+
     fn body_owner_def_id(&self) -> LocalDefId {
         self.1
     }
@@ -295,6 +324,24 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         }
     }
 
+    pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id);
+
+        // `x.use` will do one of the following
+        // * if it implements `Copy`, it will be a copy
+        // * if it implements `UseCloned`, it will be a call to `clone`
+        // * otherwise, it is a move
+        //
+        // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned`
+        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
+            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
+        } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
+            self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id);
+        } else {
+            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
+        }
+    }
+
     fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> {
         for expr in exprs {
             self.consume_expr(expr)?;
@@ -313,6 +360,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         Ok(())
     }
 
+    pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
+        debug!("consume_or_clone_expr(expr={:?})", expr);
+
+        let place_with_id = self.cat_expr(expr)?;
+        self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
+        self.walk_expr(expr)?;
+        Ok(())
+    }
+
     fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
         let place_with_id = self.cat_expr(expr)?;
         self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
@@ -366,6 +422,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 self.consume_exprs(args)?;
             }
 
+            hir::ExprKind::Use(expr, _) => {
+                self.consume_or_clone_expr(expr)?;
+            }
+
             hir::ExprKind::MethodCall(.., receiver, args, _) => {
                 // callee.m(args)
                 self.consume_expr(receiver)?;
@@ -1085,6 +1145,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                         ty::UpvarCapture::ByValue => {
                             self.consume_or_copy(&place_with_id, place_with_id.hir_id);
                         }
+                        ty::UpvarCapture::ByUse => {
+                            self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
+                        }
                         ty::UpvarCapture::ByRef(upvar_borrow) => {
                             self.delegate.borrow_mut().borrow(
                                 &place_with_id,
@@ -1386,6 +1449,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
 
             hir::ExprKind::AddrOf(..)
             | hir::ExprKind::Call(..)
+            | hir::ExprKind::Use(..)
             | hir::ExprKind::Assign(..)
             | hir::ExprKind::AssignOp(..)
             | hir::ExprKind::Closure { .. }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 9a0b22470585f..f570d0d8a0d30 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -671,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let (place, capture_kind) = match capture_clause {
                     hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
+                    hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind),
                     hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
                 };
 
@@ -1165,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let ty = match closure_clause {
             hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value
-            hir::CaptureBy::Ref => {
+            hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {
                 // For non move closure the capture kind is the max capture kind of all captures
                 // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
                 let mut max_capture_info = root_var_min_capture_list.first().unwrap().info;
@@ -1292,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
                     return Some(diagnostics_info);
                 }
-                hir::CaptureBy::Ref => {}
+                hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {}
             }
 
             return None;
@@ -1305,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for captured_place in root_var_min_capture_list.iter() {
             match captured_place.info.capture_kind {
                 // Only care about captures that are moved into the closure
-                ty::UpvarCapture::ByValue => {
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
                     projections_list.push(captured_place.place.projections.as_slice());
                     diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
                         source_expr: captured_place.info.path_expr_id,
@@ -1689,10 +1690,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             //
             // If the data will be moved out of this place, then the place will be truncated
             // at the first Deref in `adjust_for_move_closure` and then moved into the closure.
+            //
+            // For example:
+            //
+            // struct Buffer<'a> {
+            //     x: &'a String,
+            //     y: Vec<u8>,
+            // }
+            //
+            // fn get<'a>(b: Buffer<'a>) -> impl Sized + 'a {
+            //     let c = move || b.x;
+            //     drop(b);
+            //     c
+            // }
+            //
+            // Even though the closure is declared as move, when we are capturing borrowed data (in
+            // this case, *b.x) we prefer to capture by reference.
+            // Otherwise you'd get an error in 2021 immediately because you'd be trying to take
+            // ownership of the (borrowed) String or else you'd take ownership of b, as in 2018 and
+            // before, which is also an error.
             hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => {
                 ty::UpvarCapture::ByValue
             }
-            hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => {
+            hir::CaptureBy::Use { .. } if !place.deref_tys().any(Ty::is_ref) => {
+                ty::UpvarCapture::ByUse
+            }
+            hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => {
                 ty::UpvarCapture::ByRef(BorrowKind::Immutable)
             }
         }
@@ -1927,7 +1950,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
     region: ty::Region<'tcx>,
 ) -> Ty<'tcx> {
     match capture_kind {
-        ty::UpvarCapture::ByValue => ty,
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty,
         ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()),
     }
 }
@@ -2023,6 +2046,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
         ));
     }
 
+    #[instrument(skip(self), level = "debug")]
+    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
+
+        self.capture_information.push((
+            place_with_id.place.clone(),
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind: ty::UpvarCapture::ByUse,
+            },
+        ));
+    }
+
     #[instrument(skip(self), level = "debug")]
     fn borrow(
         &mut self,
@@ -2164,6 +2202,20 @@ fn adjust_for_move_closure(
     (place, ty::UpvarCapture::ByValue)
 }
 
+/// Truncate deref of any reference.
+fn adjust_for_use_closure(
+    mut place: Place<'_>,
+    mut kind: ty::UpvarCapture,
+) -> (Place<'_>, ty::UpvarCapture) {
+    let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
+
+    if let Some(idx) = first_deref {
+        truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
+    }
+
+    (place, ty::UpvarCapture::ByUse)
+}
+
 /// Adjust closure capture just that if taking ownership of data, only move data
 /// from enclosing stack frame.
 fn adjust_for_non_move_closure(
@@ -2174,7 +2226,7 @@ fn adjust_for_non_move_closure(
         place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     match kind {
-        ty::UpvarCapture::ByValue => {
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
             if let Some(idx) = contains_deref {
                 truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
             }
@@ -2219,6 +2271,7 @@ fn construct_capture_kind_reason_string<'tcx>(
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByUse => "ByUse".into(),
         ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
     };
 
@@ -2240,6 +2293,7 @@ fn construct_capture_info_string<'tcx>(
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByUse => "ByUse".into(),
         ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
     };
     format!("{place_str} -> {capture_kind_str}")
@@ -2335,8 +2389,11 @@ fn determine_capture_info(
     // expressions.
     let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
         (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
+        (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true,
         (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
-        (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
+        (ty::UpvarCapture::ByValue, _)
+        | (ty::UpvarCapture::ByUse, _)
+        | (ty::UpvarCapture::ByRef(_), _) => false,
     };
 
     if eq_capture_kind {
@@ -2346,10 +2403,20 @@ fn determine_capture_info(
         }
     } else {
         // We select the CaptureKind which ranks higher based the following priority order:
-        // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
+        // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow
         match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-            (ty::UpvarCapture::ByValue, _) => capture_info_a,
-            (_, ty::UpvarCapture::ByValue) => capture_info_b,
+            (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue)
+            | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => {
+                bug!("Same capture can't be ByUse and ByValue at the same time")
+            }
+            (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue)
+            | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse)
+            | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => {
+                capture_info_a
+            }
+            (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => {
+                capture_info_b
+            }
             (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
                 match (ref_a, ref_b) {
                     // Take LHS:
@@ -2401,7 +2468,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
         }
 
         ty::UpvarCapture::ByRef(..) => {}
-        ty::UpvarCapture::ByValue => {}
+        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
     }
 
     place.projections.truncate(len);
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 74663e6b4bbe1..cd4106ebf83af 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> {
         self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
     }
 
+    pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
+    }
+
     /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
     pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index fd6b3e90adabc..91c7922638de5 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -159,7 +159,10 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
         ExprKind::Path(..) => false,
 
         // Calls return rvalues.
-        ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
+        ExprKind::Call(..)
+        | ExprKind::MethodCall(..)
+        | ExprKind::Use(..)
+        | ExprKind::Binary(..) => true,
 
         // Inner blocks are rvalues.
         ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1302027aabb36..cf623459898ac 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1533,6 +1533,11 @@ rustc_queries! {
     query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Copy`", env.value }
     }
+    /// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`,
+    /// `ty.is_use_cloned()`, etc, since that will prune the environment where possible.
+    query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
+        desc { "computing whether `{}` is `UseCloned`", env.value }
+    }
     /// Query backing `Ty::is_sized`.
     query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Sized`", env.value }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index e5592de81cd78..c9e7331660ffb 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -312,6 +312,14 @@ pub enum ExprKind<'tcx> {
         /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
         fn_span: Span,
     },
+    /// A use expression `x.use`.
+    ByUse {
+        /// The expression on which use is applied.
+        expr: ExprId,
+        /// The span of use, without the dot and receiver
+        /// (e.g. `use` in `x.use`).
+        span: Span,
+    },
     /// A *non-overloaded* dereference.
     Deref {
         arg: ExprId,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index a9df4d1625be3..d208692f4e711 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -59,6 +59,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_expr(&visitor.thir()[arg]);
             }
         }
+        ByUse { expr, span: _ } => {
+            visitor.visit_expr(&visitor.thir()[expr]);
+        }
         Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
         Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
             visitor.visit_expr(&visitor.thir()[lhs]);
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 3605f2402e7ff..5d9b1ddfa38ea 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -51,6 +51,9 @@ pub enum UpvarCapture {
     /// depending on inference.
     ByValue,
 
+    /// Upvar is captured by use. This is true when the closure is labeled `use`.
+    ByUse,
+
     /// Upvar is captured by reference.
     ByRef(BorrowKind),
 }
@@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> {
 
     pub fn is_by_ref(&self) -> bool {
         match self.info.capture_kind {
-            ty::UpvarCapture::ByValue => false,
+            ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false,
             ty::UpvarCapture::ByRef(..) => true,
         }
     }
@@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
         if !self.is_closure_like(def_id.to_def_id()) {
             return &[];
-        };
+        }
         self.closure_typeinfo(def_id).captures
     }
 }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 237aa66f486f8..0c68913904fc3 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> {
         ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
     }
 
+    /// Checks whether `ty: UseCloned` holds while ignoring region constraints.
+    ///
+    /// This function should not be used if there is an `InferCtxt` available.
+    /// Use `InferCtxt::type_is_copy_modulo_regions` instead.
+    pub fn type_is_use_cloned_modulo_regions(
+        self,
+        typing_env: ty::TypingEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty))
+    }
+
     /// Returns the deeply last field of nested structures, or the same type if
     /// not a structure at all. Corresponds to the only possible unsized field,
     /// and its type can be used to determine unsizing strategy.
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
index 581f45db6c483..50ca924baf9c8 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
@@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Yield { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::WrapUnsafeBinder { .. } => {
                 // these are not places, so we need to make a temporary.
                 debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index 2c9a1de7f9978..97d34b85f50da 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 block.and(Rvalue::Use(operand))
             }
+
+            ExprKind::ByUse { expr, span: _ } => {
+                let operand = unpack!(
+                    block =
+                        this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
+                );
+                block.and(Rvalue::Use(operand))
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs
index ca55d36bfc659..34524aed40678 100644
--- a/compiler/rustc_mir_build/src/builder/expr/category.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/category.rs
@@ -56,6 +56,7 @@ impl Category {
             | ExprKind::RawBorrow { .. }
             | ExprKind::Yield { .. }
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
 
             ExprKind::Array { .. }
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index 72443e2f60ddc..333e69475c508 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -4,11 +4,14 @@ use rustc_ast::{AsmMacro, InlineAsmOptions};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::thir::*;
-use rustc_middle::ty::CanonicalUserTypeAnnotation;
+use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
+use rustc_span::DUMMY_SP;
 use rustc_span::source_map::Spanned;
+use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::{debug, instrument};
 
 use crate::builder::expr::category::{Category, RvalueFunc};
@@ -289,6 +292,57 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.diverge_from(block);
                 success.unit()
             }
+            ExprKind::ByUse { expr, span } => {
+                let place = unpack!(block = this.as_place(block, expr));
+                let ty = place.ty(&this.local_decls, this.tcx).ty;
+
+                if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) {
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        destination,
+                        Rvalue::Use(Operand::Copy(place)),
+                    );
+                    block.unit()
+                } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
+                    // Convert `expr.use` to a call like `Clone::clone(&expr)`
+                    let success = this.cfg.start_new_block();
+                    let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
+                    let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
+                    let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
+                    let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
+                    let ref_place = this.temp(ref_ty, span);
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        ref_place,
+                        Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
+                    );
+                    this.cfg.terminate(
+                        block,
+                        source_info,
+                        TerminatorKind::Call {
+                            func,
+                            args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }]
+                                .into(),
+                            destination,
+                            target: Some(success),
+                            unwind: UnwindAction::Unreachable,
+                            call_source: CallSource::Misc,
+                            fn_span: expr_span,
+                        },
+                    );
+                    success.unit()
+                } else {
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        destination,
+                        Rvalue::Use(Operand::Move(place)),
+                    );
+                    block.unit()
+                }
+            }
             ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
             ExprKind::Borrow { arg, borrow_kind } => {
                 // We don't do this in `as_rvalue` because we use `as_place`
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 949559549345f..ff2b59ee07d20 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
         .map(|captured_place| {
             let name = captured_place.to_symbol();
             match captured_place.info.capture_kind {
-                ty::UpvarCapture::ByValue => name,
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
                 ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
             }
         })
@@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let mut projs = closure_env_projs.clone();
                 projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
                 match capture {
-                    ty::UpvarCapture::ByValue => {}
+                    ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     ty::UpvarCapture::ByRef(..) => {
                         projs.push(ProjectionElem::Deref);
                     }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index c2eafd0a74e65..d78c874c76607 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -451,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::Tuple { .. }
             | ExprKind::Unary { .. }
             | ExprKind::Call { .. }
+            | ExprKind::ByUse { .. }
             | ExprKind::Assign { .. }
             | ExprKind::AssignOp { .. }
             | ExprKind::Break { .. }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 7139516702e99..e46e8c9871a5a 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -464,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 }
             }
 
+            hir::ExprKind::Use(expr, span) => {
+                ExprKind::ByUse { expr: self.mirror_expr(expr), span }
+            }
+
             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
                 ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
             }
@@ -648,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 }
             },
 
-            hir::ExprKind::Closure { .. } => {
+            hir::ExprKind::Closure(hir::Closure { .. }) => {
                 let closure_ty = self.typeck_results.expr_ty(expr);
                 let (def_id, args, movability) = match *closure_ty.kind() {
                     ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
@@ -1248,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> {
 
         match upvar_capture {
             ty::UpvarCapture::ByValue => captured_place_expr,
+            ty::UpvarCapture::ByUse => {
+                let span = captured_place_expr.span;
+                let expr_id = self.thir.exprs.push(captured_place_expr);
+
+                Expr {
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                    ty: upvar_ty,
+                    span: closure_expr.span,
+                    kind: ExprKind::ByUse { expr: expr_id, span },
+                }
+            }
             ty::UpvarCapture::ByRef(upvar_borrow) => {
                 let borrow_kind = match upvar_borrow {
                     ty::BorrowKind::Immutable => BorrowKind::Shared,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 954d0cf97abef..dadd1e8546117 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             | Borrow { .. }
             | Box { .. }
             | Call { .. }
+            | ByUse { .. }
             | Closure { .. }
             | ConstBlock { .. }
             | ConstParam { .. }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index cd56d93afcf75..16cef0ec3acbc 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
 
                 print_indented!(self, "}", depth_lvl);
             }
+            ByUse { expr, span } => {
+                print_indented!(self, "ByUse {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
             Deref { arg } => {
                 print_indented!(self, "Deref {", depth_lvl);
                 self.print_expr(*arg, depth_lvl + 1);
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 0f5fcb0d8eb99..c79ea14d6f64f 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -170,7 +170,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
             // this when building the field projection in the MIR body later on.
             let mut parent_capture_ty = parent_capture.place.ty();
             parent_capture_ty = match parent_capture.info.capture_kind {
-                ty::UpvarCapture::ByValue => parent_capture_ty,
+                ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty,
                 ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
                     tcx,
                     tcx.lifetimes.re_erased,
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 1d5b59421706f..6d4308cda1a60 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -26,6 +26,11 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
     .suggestion = try switching the order
 
+parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later
+
+parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
+    .suggestion = try switching the order
+
 parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
     .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
 
@@ -348,6 +353,9 @@ parse_incorrect_use_of_await = incorrect use of `await`
 
 parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation
 
+parse_incorrect_use_of_use = incorrect use of `use`
+    .parentheses_suggestion = `use` is not a method call, try removing the parentheses
+
 parse_incorrect_visibility_restriction = incorrect visibility restriction
     .help = some possible visibility restrictions are:
             `pub(crate)`: visible only on the current crate
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 8d2fd595942c6..e090d9cf7600e 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_incorrect_use_of_use)]
+pub(crate) struct IncorrectUseOfUse {
+    #[primary_span]
+    #[suggestion(
+        parse_parentheses_suggestion,
+        style = "verbose",
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(
     parse_incorrect_use_of_await_postfix_suggestion,
@@ -1499,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_async_use_order_incorrect)]
+pub(crate) struct AsyncUseOrderIncorrect {
+    #[primary_span]
+    #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_double_colon_in_bound)]
 pub(crate) struct DoubleColonInBound {
@@ -1667,6 +1688,13 @@ pub(crate) struct AsyncMoveBlockIn2015 {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_async_use_block_in_2015)]
+pub(crate) struct AsyncUseBlockIn2015 {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_async_bound_modifier_in_2015)]
 pub(crate) struct AsyncBoundModifierIn2015 {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 94db43bb59f81..bb227a58cf19d 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -31,15 +31,15 @@ use super::{
     SeqSep, TokenType,
 };
 use crate::errors::{
-    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
-    BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
-    ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
-    ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
-    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
+    AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
+    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
+    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
+    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
     GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
     HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
-    IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
-    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+    IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
+    QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
     StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
     SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
     UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
@@ -572,10 +572,17 @@ impl<'a> Parser<'a> {
             return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
         }
 
-        if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
-            // The 2015 edition is in use because parsing of `async move` has failed.
+        if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
+            && self.prev_token.is_keyword(kw::Async)
+        {
+            // The 2015 edition is in use because parsing of `async move` or `async use` has failed.
             let span = self.prev_token.span.to(self.token.span);
-            return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
+            if self.token.is_keyword(kw::Move) {
+                return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
+            } else {
+                // kw::Use
+                return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
+            }
         }
 
         let expect = tokens_to_string(&expected);
@@ -1991,7 +1998,7 @@ impl<'a> Parser<'a> {
             self.parse_expr()
         }
         .map_err(|mut err| {
-            err.span_label(await_sp, "while parsing this incorrect await expression");
+            err.span_label(await_sp, format!("while parsing this incorrect await expression"));
             err
         })?;
         Ok((expr.span, expr, is_question))
@@ -2030,6 +2037,21 @@ impl<'a> Parser<'a> {
             self.dcx().emit_err(IncorrectUseOfAwait { span });
         }
     }
+    ///
+    /// If encountering `x.use()`, consumes and emits an error.
+    pub(super) fn recover_from_use(&mut self) {
+        if self.token == token::OpenDelim(Delimiter::Parenthesis)
+            && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
+        {
+            // var.use()
+            let lo = self.token.span;
+            self.bump(); // (
+            let span = lo.to(self.token.span);
+            self.bump(); // )
+
+            self.dcx().emit_err(IncorrectUseOfUse { span });
+        }
+    }
 
     pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
         let is_try = self.token.is_keyword(kw::Try);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0a08c6faeb486..b37dd64fbed6b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -778,6 +778,7 @@ impl<'a> Parser<'a> {
                     ExprKind::MethodCall(_) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_, _) => "`.await`",
+                    ExprKind::Use(_, _) => "`.use`",
                     ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
                     ExprKind::Err(_) => return Ok(with_postfix),
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
@@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> {
             return Ok(self.mk_await_expr(self_arg, lo));
         }
 
+        if self.eat_keyword(exp!(Use)) {
+            let use_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
+            return Ok(self.mk_use_expr(self_arg, lo));
+        }
+
         // Post-fix match
         if self.eat_keyword(exp!(Match)) {
             let match_span = self.prev_token.span;
@@ -1397,6 +1404,7 @@ impl<'a> Parser<'a> {
             } else if this.check_path() {
                 this.parse_expr_path_start()
             } else if this.check_keyword(exp!(Move))
+                || this.check_keyword(exp!(Use))
                 || this.check_keyword(exp!(Static))
                 || this.check_const_closure()
             {
@@ -2388,7 +2396,7 @@ impl<'a> Parser<'a> {
         Ok(closure)
     }
 
-    /// Parses an optional `move` prefix to a closure-like construct.
+    /// Parses an optional `move` or `use` prefix to a closure-like construct.
     fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
         if self.eat_keyword(exp!(Move)) {
             let move_kw_span = self.prev_token.span;
@@ -2401,6 +2409,16 @@ impl<'a> Parser<'a> {
             } else {
                 Ok(CaptureBy::Value { move_kw: move_kw_span })
             }
+        } else if self.eat_keyword(exp!(Use)) {
+            let use_kw_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
+            // Check for `use async` and recover
+            if self.check_keyword(exp!(Async)) {
+                let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
+                Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
+            } else {
+                Ok(CaptureBy::Use { use_kw: use_kw_span })
+            }
         } else {
             Ok(CaptureBy::Ref)
         }
@@ -3415,7 +3433,7 @@ impl<'a> Parser<'a> {
         self.is_keyword_ahead(lookahead, &[kw])
             && ((
                 // `async move {`
-                self.is_keyword_ahead(lookahead + 1, &[kw::Move])
+                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
                     && self.look_ahead(lookahead + 2, |t| {
                         *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
                     })
@@ -3818,6 +3836,13 @@ impl<'a> Parser<'a> {
         await_expr
     }
 
+    fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
+        let span = lo.to(self.prev_token.span);
+        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
+        self.recover_from_use();
+        use_expr
+    }
+
     pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
         P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
     }
@@ -3966,6 +3991,7 @@ impl MutVisitor for CondChecker<'_> {
             }
             ExprKind::Unary(_, _)
             | ExprKind::Await(_, _)
+            | ExprKind::Use(_, _)
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Range(_, _, _)
             | ExprKind::Try(_)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 3f642a7ac1fdd..678376aee4f82 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -209,7 +209,7 @@ impl<'a> Parser<'a> {
         let check_pub = def == &Defaultness::Final;
         let mut def_ = || mem::replace(def, Defaultness::Final);
 
-        let info = if self.eat_keyword_case(exp!(Use), case) {
+        let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
             self.parse_use_item()?
         } else if self.check_fn_front_matter(check_pub, case) {
             // FUNCTION ITEM
@@ -1277,6 +1277,21 @@ impl<'a> Parser<'a> {
         None
     }
 
+    fn is_use_closure(&self) -> bool {
+        if self.token.is_keyword(kw::Use) {
+            // Check if this could be a closure.
+            self.look_ahead(1, |token| {
+                // Move or Async here would be an error but still we're parsing a closure
+                let dist =
+                    if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 };
+
+                self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr))
+            })
+        } else {
+            false
+        }
+    }
+
     fn is_unsafe_foreign_mod(&self) -> bool {
         self.token.is_keyword(kw::Unsafe)
             && self.is_keyword_ahead(1, &[kw::Extern])
@@ -1290,7 +1305,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(exp!(Static)) {
             // Check if this could be a closure.
             !self.look_ahead(1, |token| {
-                if token.is_keyword(kw::Move) {
+                if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
                     return true;
                 }
                 matches!(token.kind, token::Or | token::OrOr)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7dabc28c6454c..4ec8d9e5e49e0 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -813,9 +813,9 @@ impl<'a> Parser<'a> {
         self.is_keyword_ahead(0, &[kw::Const])
             && self.look_ahead(1, |t| match &t.kind {
                 // async closures do not work with const closures, so we do not parse that here.
-                token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => {
-                    true
-                }
+                token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No)
+                | token::OrOr
+                | token::Or => true,
                 _ => false,
             })
     }
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 92ea49f18e5d1..e610b404d0169 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -328,6 +328,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Array,
                 Call,
                 MethodCall,
+                Use,
                 Tup,
                 Binary,
                 Unary,
@@ -626,7 +627,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
             (self, e, e.kind, None, ast, Expr, ExprKind),
             [
                 Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
-                If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
+                If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
                 InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
                 Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 24dc018c66124..822804893fe2a 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -426,6 +426,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::Array(..)
             | hir::ExprKind::Call(..)
             | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Use(..)
             | hir::ExprKind::Tup(..)
             | hir::ExprKind::Binary(..)
             | hir::ExprKind::AddrOf(..)
@@ -705,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                             );
                             self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
                         }
-                        ty::UpvarCapture::ByValue => {}
+                        ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     }
                 }
             }
@@ -1031,6 +1032,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_expr(receiver, succ)
             }
 
+            hir::ExprKind::Use(expr, _) => {
+                let succ = self.check_is_ty_uninhabited(expr, succ);
+                self.propagate_through_expr(expr, succ)
+            }
+
             hir::ExprKind::Tup(exprs) => self.propagate_through_exprs(exprs, succ),
 
             hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
@@ -1418,6 +1424,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         // no correctness conditions related to liveness
         hir::ExprKind::Call(..)
         | hir::ExprKind::MethodCall(..)
+        | hir::ExprKind::Use(..)
         | hir::ExprKind::Match(..)
         | hir::ExprKind::Loop(..)
         | hir::ExprKind::Index(..)
@@ -1493,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
         for (&var_hir_id, min_capture_list) in closure_min_captures {
             for captured_place in min_capture_list {
                 match captured_place.info.capture_kind {
-                    ty::UpvarCapture::ByValue => {}
+                    ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
                     ty::UpvarCapture::ByRef(..) => continue,
                 };
                 let span = captured_place.get_capture_kind_span(self.ir.tcx);
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index cb17b0f6cf528..d35aedf9a5647 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -182,6 +182,7 @@ impl CheckInlineAssembly {
             | ExprKind::Array(..)
             | ExprKind::Call(..)
             | ExprKind::MethodCall(..)
+            | ExprKind::Use(..)
             | ExprKind::Tup(..)
             | ExprKind::Binary(..)
             | ExprKind::Unary(..)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 522bccb1acb05..a8c38d8244ded 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -859,6 +859,7 @@ symbols! {
         eprint_macro,
         eprintln_macro,
         eq,
+        ergonomic_clones,
         ermsb_target_feature,
         exact_div,
         except,
@@ -2181,6 +2182,7 @@ symbols! {
         unwrap,
         unwrap_binder,
         unwrap_or,
+        use_cloned,
         use_extern_macros,
         use_nested_groups,
         used,
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f373706b2960c..5cf0600ade8b4 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> {
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id)
     }
 
+    fn type_is_use_cloned_modulo_regions(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let ty = self.resolve_vars_if_possible(ty);
+        let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None);
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
+    }
+
     fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl
index de2c3b63997ed..8bc7bf10865f5 100644
--- a/compiler/rustc_ty_utils/messages.ftl
+++ b/compiler/rustc_ty_utils/messages.ftl
@@ -14,6 +14,8 @@ ty_utils_borrow_not_supported = borrowing is not supported in generic constants
 
 ty_utils_box_not_supported = allocations are not allowed in generic constants
 
+ty_utils_by_use_not_supported = .use is not allowed in generic constants
+
 ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
 
 ty_utils_const_block_not_supported = const blocks are not supported in generic constants
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index 2157ab3c4022c..20646cf9a826c 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty
     is_item_raw(tcx, query, LangItem::Copy)
 }
 
+fn is_use_cloned_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
+) -> bool {
+    is_item_raw(tcx, query, LangItem::UseCloned)
+}
+
 fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Sized)
 }
@@ -33,5 +40,12 @@ fn is_item_raw<'tcx>(
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
+    *providers = Providers {
+        is_copy_raw,
+        is_use_cloned_raw,
+        is_sized_raw,
+        is_freeze_raw,
+        is_unpin_raw,
+        ..*providers
+    };
 }
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index ece796b3c71ce..b275cd382ab83 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -230,7 +230,9 @@ fn recurse_build<'tcx>(
             error(GenericConstantTooComplexSub::LoopNotSupported(node.span))?
         }
         ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?,
-
+        ExprKind::ByUse { .. } => {
+            error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))?
+        }
         ExprKind::Unary { .. } => unreachable!(),
         // we handle valid unary/binary ops above
         ExprKind::Binary { .. } => {
@@ -317,6 +319,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
             | thir::ExprKind::Box { .. }
             | thir::ExprKind::If { .. }
             | thir::ExprKind::Call { .. }
+            | thir::ExprKind::ByUse { .. }
             | thir::ExprKind::Deref { .. }
             | thir::ExprKind::Binary { .. }
             | thir::ExprKind::LogicalOp { .. }
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 8877bb45ceb22..0298e7e0e9511 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -55,6 +55,8 @@ pub(crate) enum GenericConstantTooComplexSub {
     BoxNotSupported(#[primary_span] Span),
     #[label(ty_utils_binary_not_supported)]
     BinaryNotSupported(#[primary_span] Span),
+    #[label(ty_utils_by_use_not_supported)]
+    ByUseNotSupported(#[primary_span] Span),
     #[label(ty_utils_logical_op_not_supported)]
     LogicalOpNotSupported(#[primary_span] Span),
     #[label(ty_utils_assign_not_supported)]
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cb93100f56cf0..265b68d3b0eb4 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -56,6 +56,7 @@
 //! [`Rc`]: rc
 //! [`RefCell`]: core::cell
 
+#![allow(incomplete_features)]
 #![allow(unused_attributes)]
 #![stable(feature = "alloc", since = "1.36.0")]
 #![doc(
@@ -113,6 +114,7 @@
 #![feature(deprecated_suggestion)]
 #![feature(deref_pure_trait)]
 #![feature(dispatch_from_dyn)]
+#![feature(ergonomic_clones)]
 #![feature(error_generic_member_access)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 09206c2f8b290..5847bd8f28138 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -245,6 +245,7 @@ use core::any::Any;
 use core::cell::Cell;
 #[cfg(not(no_global_oom_handling))]
 use core::clone::CloneToUninit;
+use core::clone::UseCloned;
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
@@ -2333,6 +2334,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Rc<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Rc<T, A> {}
+
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Default> Default for Rc<T> {
@@ -3496,6 +3500,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
+
 #[stable(feature = "rc_weak", since = "1.4.0")]
 impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index dba1449347ac0..ddd0677ee3507 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -11,6 +11,7 @@
 use core::any::Any;
 #[cfg(not(no_global_oom_handling))]
 use core::clone::CloneToUninit;
+use core::clone::UseCloned;
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
@@ -2197,6 +2198,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Arc<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Arc<T, A> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
     type Target = T;
@@ -3158,6 +3162,9 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T: ?Sized, A: Allocator + Clone> UseCloned for Weak<T, A> {}
+
 #[stable(feature = "downgraded_weak", since = "1.10.0")]
 impl<T> Default for Weak<T> {
     /// Constructs a new `Weak<T>`, without allocating memory.
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 00300328b64c1..4e18ab1c7cf5d 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -184,6 +184,59 @@ pub macro Clone($item:item) {
     /* compiler built-in */
 }
 
+/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted)
+///
+/// Cloning an object implementing this trait should in general:
+/// - be O(1) (constant) time regardless of the amount of data managed by the object,
+/// - not require a memory allocation,
+/// - not require copying more than roughly 64 bytes (a typical cache line size),
+/// - not block the current thread,
+/// - not have any semantic side effects (e.g. allocating a file descriptor), and
+/// - not have overhead larger than a couple of atomic operations.
+///
+/// The `UseCloned` trait does not provide a method; instead, it indicates that
+/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax.
+///
+/// ## .use postfix syntax
+///
+/// Values can be `.use`d by adding `.use` postfix to the value you want to use.
+///
+/// ```ignore (this won't work until we land use)
+/// fn foo(f: Foo) {
+///     // if `Foo` implements `Copy` f would be copied into x.
+///     // if `Foo` implements `UseCloned` f would be cloned into x.
+///     // otherwise f would be moved into x.
+///     let x = f.use;
+///     // ...
+/// }
+/// ```
+///
+/// ## use closures
+///
+/// Use closures allow captured values to be automatically used.
+/// This is similar to have a closure that you would call `.use` over each captured value.
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+#[cfg_attr(not(bootstrap), lang = "use_cloned")]
+pub trait UseCloned: Clone {
+    // Empty.
+}
+
+macro_rules! impl_use_cloned {
+    ($($t:ty)*) => {
+        $(
+            #[unstable(feature = "ergonomic_clones", issue = "132290")]
+            impl UseCloned for $t {}
+        )*
+    }
+}
+
+impl_use_cloned! {
+    usize u8 u16 u32 u64 u128
+    isize i8 i16 i32 i64 i128
+             f16 f32 f64 f128
+    bool char
+}
+
 // FIXME(aburka): these structs are used solely by #[derive] to
 // assert that every component of a type implements Clone or Copy.
 //
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index 2a47c89e2aee2..9de6b349d946e 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -405,6 +405,8 @@ macro_rules! define_bignum {
             }
         }
 
+        impl crate::clone::UseCloned for $name {}
+
         impl crate::fmt::Debug for $name {
             fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
                 let sz = if self.size < 1 { 1 } else { self.size };
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index a967b72c4fa9b..5b997d44278cc 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1,6 +1,7 @@
 //! Definitions of integer that is known not to equal zero.
 
 use super::{IntErrorKind, ParseIntError};
+use crate::clone::UseCloned;
 use crate::cmp::Ordering;
 use crate::hash::{Hash, Hasher};
 use crate::marker::{Freeze, StructuralPartialEq};
@@ -183,6 +184,9 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
+
 #[stable(feature = "nonzero", since = "1.28.0")]
 impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
 
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index a9f06b92ad5dd..f668c6f067246 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2050,6 +2050,9 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T> crate::clone::UseCloned for Option<T> where T: crate::clone::UseCloned {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for Option<T> {
     /// Returns [`None`][Option::None].
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 92b5cba153166..ee98a47523fef 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1744,6 +1744,14 @@ where
     }
 }
 
+#[unstable(feature = "ergonomic_clones", issue = "132290")]
+impl<T, E> crate::clone::UseCloned for Result<T, E>
+where
+    T: crate::clone::UseCloned,
+    E: crate::clone::UseCloned,
+{
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, E> IntoIterator for Result<T, E> {
     type Item = T;
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index bdd330611de3d..5ac3dbc3e9852 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2121,8 +2121,8 @@ mod unsafe_keyword {}
 
 #[doc(keyword = "use")]
 //
-/// Import or rename items from other crates or modules, or specify precise capturing
-/// with `use<..>`.
+/// Import or rename items from other crates or modules, use values under ergonomic clones
+/// semantic, or specify precise capturing with `use<..>`.
 ///
 /// ## Importing items
 ///
@@ -2205,6 +2205,11 @@ mod unsafe_keyword {}
 ///
 /// For more details about precise capturing, see the [Reference][ref-impl-trait].
 ///
+/// ## Ergonomic clones
+///
+/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the
+/// value implements `UseCloned` or moving it otherwise.
+///
 /// [`crate`]: keyword.crate.html
 /// [`self`]: keyword.self.html
 /// [`super`]: keyword.super.html
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 8d1e893cb1af2..33ba401d60c21 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
         }
     }
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
         if cmt.place.projections.is_empty() {
             if let PlaceBase::Local(lid) = cmt.place.base {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 39e5e140b7a40..fb5d49a100475 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> {
 impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
         if bk == ty::BorrowKind::Mutable {
             if let PlaceBase::Local(id) = cmt.place.base {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index b679fdfadc3a9..dd7a6f77acff5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>(
         | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
         ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
+        ExprKind::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => {
             never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id)
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 09440c396ee16..d0905733ab506 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -99,7 +99,7 @@ where
                 });
                 if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
                     match captures.get(l) {
-                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+                        Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
                         Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
                             return None;
                         },
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index a80977459f21d..f51bdc78f8a51 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate {
         }
     }
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {}
 
     fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d5c5679c990df..dc10de24bc8c7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
+    fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
+
     #[allow(clippy::if_same_then_else)]
     fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
         self.prev_bind = None;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 380cc380ad0f2..dc85176ebb9e9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
         self.move_common(cmt);
     }
 
+    fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}
 
     fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 5737a91031db2..03b907ebdf4d8 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet {
         }
 
         fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
+        fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {}
         fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
@@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet {
         }
 
         fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
+        fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
         fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {}
         fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {}
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index de9f055863cb2..75b18bc651e2a 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>(
                         .then_some(())
                         .and_then(|()| none_captures.get(local_id))
                 }) {
-                    Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+                    Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None,
                     Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
                     Some(CaptureKind::Ref(Mutability::Not)) | None => (),
                 }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 76b9bbbd32fde..6f6683eb97123 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
 
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 5fc166438e84a..9d8c161873c05 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Tup({elements})");
                 self.slice(elements, |e| self.expr(e));
             },
+            ExprKind::Use(expr, _) => {
+                bind!(self, expr);
+                kind!("Use({expr})");
+                self.expr(expr);
+            },
             ExprKind::Binary(op, left, right) => {
                 bind!(self, op, left, right);
                 kind!("Binary({op}, {left}, {right})");
@@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             }) => {
                 let capture_clause = match capture_clause {
                     CaptureBy::Value { .. } => "Value { .. }",
+                    CaptureBy::Use { .. } => "Use { .. }",
                     CaptureBy::Ref => "Ref",
                 };
 
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index aaea8d71efbef..4543a20cc2cd4 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::ConstBlock(_)
                 | ExprKind::Array(_)
                 | ExprKind::Tup(_)
+                | ExprKind::Use(..)
                 | ExprKind::Lit(_)
                 | ExprKind::Cast(..)
                 | ExprKind::Type(..)
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 4bd86a2533518..dd0ac224e4560 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
+            (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr),
             (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt),
             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re),
@@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 | &ExprKind::Ret(..)
                 | &ExprKind::Struct(..)
                 | &ExprKind::Tup(..)
+                | &ExprKind::Use(..)
                 | &ExprKind::Type(..)
                 | &ExprKind::Unary(..)
                 | &ExprKind::Yield(..)
@@ -1053,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Tup(tup) => {
                 self.hash_exprs(tup);
             },
+            ExprKind::Use(expr, _) => {
+                self.hash_expr(expr);
+            },
             ExprKind::Unary(lop, le) => {
                 std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index d850cc410008d..723ae9b01a803 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1129,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>(
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum CaptureKind {
     Value,
+    Use,
     Ref(Mutability),
 }
 impl CaptureKind {
@@ -1141,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind {
     fn bitor(self, rhs: Self) -> Self::Output {
         match (self, rhs) {
             (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
+            (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use,
             (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
             | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
             (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
@@ -1220,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 },
                 ExprKind::Let(let_expr) => {
                     let mutability = match pat_capture_kind(cx, let_expr.pat) {
-                        CaptureKind::Value => Mutability::Not,
+                        CaptureKind::Value | CaptureKind::Use => Mutability::Not,
                         CaptureKind::Ref(m) => m,
                     };
                     return CaptureKind::Ref(mutability);
@@ -1229,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                     let mut mutability = Mutability::Not;
                     for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
                         match capture {
-                            CaptureKind::Value => break,
+                            CaptureKind::Value | CaptureKind::Use => break,
                             CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
                             CaptureKind::Ref(Mutability::Not) => (),
                         }
@@ -1239,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 _ => break,
             },
             Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {
-                CaptureKind::Value => break,
+                CaptureKind::Value | CaptureKind::Use => break,
                 capture @ CaptureKind::Ref(_) => return capture,
             },
             _ => break,
@@ -1294,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
                         if !self.locals.contains(&local_id) {
                             let capture = match capture.info.capture_kind {
                                 UpvarCapture::ByValue => CaptureKind::Value,
+                                UpvarCapture::ByUse => CaptureKind::Use,
                                 UpvarCapture::ByRef(kind) => match kind {
                                     BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not),
                                     BorrowKind::UniqueImmutable | BorrowKind::Mutable => {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 4a9ab17d4a609..24b4f0d9e6d81 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -147,6 +147,7 @@ impl<'a> Sugg<'a> {
             | ExprKind::Become(..)
             | ExprKind::Struct(..)
             | ExprKind::Tup(..)
+            | ExprKind::Use(..)
             | ExprKind::Err(_)
             | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
             ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
@@ -217,6 +218,7 @@ impl<'a> Sugg<'a> {
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
             | ast::ExprKind::Tup(..)
+            | ast::ExprKind::Use(..)
             | ast::ExprKind::Array(..)
             | ast::ExprKind::While(..)
             | ast::ExprKind::Await(..)
@@ -835,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
 impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
         if let PlaceBase::Local(id) = cmt.place.base {
             let map = self.cx.tcx.hir();
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 3bf518f7fe706..a079fd940c009 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -66,6 +66,8 @@ impl MutVarsDelegate {
 impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
+    fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
         if bk == ty::BorrowKind::Mutable {
             self.update(cmt);
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 2ac0efd7e392d..63dd00f2de0fb 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                     helper(typeck, true, arg, f)?;
                 }
             },
+            ExprKind::Use(expr, _) => {
+                helper(typeck, true, expr, f)?;
+            },
             ExprKind::Index(borrowed, consumed, _)
             | ExprKind::Assign(borrowed, consumed, _)
             | ExprKind::AssignOp(_, borrowed, consumed) => {
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 16b7e7aa709dd..eff2d2e3ff4a3 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -137,6 +137,10 @@ pub(crate) fn format_expr(
         ast::ExprKind::Tup(ref items) => {
             rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
         }
+        ast::ExprKind::Use(_, _) => {
+            // FIXME: properly implement this
+            Ok(context.snippet(expr.span()).to_owned())
+        }
         ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
         ast::ExprKind::If(..)
         | ast::ExprKind::ForLoop { .. }
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index ba4a4c045f1c2..fe716c186389f 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -513,6 +513,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Become(..)
         | ast::ExprKind::Yeet(..)
         | ast::ExprKind::Tup(..)
+        | ast::ExprKind::Use(..)
         | ast::ExprKind::Type(..)
         | ast::ExprKind::Yield(None)
         | ast::ExprKind::Underscore => false,
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 905e1249d972d..152a6f3a41e64 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 af5cc515bb224..53f1b827f9c6a 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 0000000000000..ad2bfd97cd1b5
--- /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 0000000000000..d3b2071b9f91f
--- /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 0000000000000..b218e6b242e19
--- /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 0000000000000..e891686b550ae
--- /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 0000000000000..fd832fbc8d295
--- /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 0000000000000..01d3b08ffa27c
--- /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 0000000000000..6b4de824df9ef
--- /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 0000000000000..cbb13e56a18a8
--- /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 0000000000000..4df1df1378b8d
--- /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 0000000000000..24060f3ed3b8b
--- /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 0000000000000..40f1200695cc3
--- /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 0000000000000..1e57063245272
--- /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 0000000000000..59aa61f581d92
--- /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 0000000000000..f7c742d33fda9
--- /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 0000000000000..b2f99efa1e666
--- /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 0000000000000..5a42ae63afaf1
--- /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 0000000000000..ef05fffd47993
--- /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 0000000000000..1cb5b8a7ec3f6
--- /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 0000000000000..3ff33cf701748
--- /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 0000000000000..fc364fb594b2c
--- /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 0000000000000..a8267ac5359f1
--- /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 0000000000000..0b3bfae0608ab
--- /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 0000000000000..c37cb71394be8
--- /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 0000000000000..e80d0d4b649a5
--- /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 0000000000000..283405c79d61e
--- /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 0000000000000..c24a4cc5094be
--- /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 0000000000000..5f48059ebff29
--- /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 0000000000000..4260c252d9dd9
--- /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 0000000000000..8f962f079df75
--- /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 0000000000000..37ef5c37029cf
--- /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 0000000000000..4b7a92534eda1
--- /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 0000000000000..c2e44064cfad7
--- /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 0000000000000..cf92f2f28df80
--- /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 2fde37ce6acef..b08c830bfc76f 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 b65de4eac3f80..f51ee92626f53 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 a002d54dc9112..2507326fb2854 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 10af39b700748..1f5004ad0998d 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 6e03bbb586959..48dea071ae64e 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