diff --git a/text/3512-closure-move-bindings.md b/text/3512-closure-move-bindings.md
new file mode 100644
index 00000000000..0f4313246a2
--- /dev/null
+++ b/text/3512-closure-move-bindings.md
@@ -0,0 +1,288 @@
+- Feature `closure_move_bindings`
+- Start Date: 2023-10-09
+- RFC PR: [rust-lang/rfcs#3512](https://github.com/rust-lang/rfcs/pull/3512)
+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
+
+# Summary
+[summary]: #summary
+
+Adds the syntax `move(bindings) |...| ...`
+to explicitly specify how to capture bindings into a closure.
+
+# Motivation
+[motivation]: #motivation
+
+Currently there are two ways to capture local bindings into a closure,
+namely by reference (`|| foo`) and by moving (`move || foo`).
+This mechanism has several ergonomic problems:
+
+- It is not possible to move some bindings and reference the others.
+To do so, one must define another binding that borrows the value
+and move it into the closure:
+
+```rs
+{
+ let foo = &foo;
+ move || run(foo, bar)
+}
+```
+
+- It is a very frequent scenario to clone a value into a closure
+(especially common with `Rc`/`Arc`-based values),
+but even the simplest scenario requires three lines of boilerplate:
+
+```rs
+{
+ let foo = foo.clone();
+ move || foo.run()
+}
+```
+
+This RFC proposes a more concise syntax to express these moving semantics.
+
+# Guide-level explanation
+[guide-level-explanation]: #guide-level-explanation
+
+A closure may capture bindings in its defining scope.
+By default, bindings are captured by usage,
+i.e. by the first possible of shared reference, mutable reference or move.
+
+```rs
+let mut foo = 1;
+let mut closure = || { foo = 2; };
+closure();
+dbg!(foo); // foo is now 2
+```
+
+You can add a `move` keyword in front of the closure
+to indicate that all captured bindings are always moved into the closure,
+useful for avoiding references to local variables:
+
+```rs
+let mut foo = 1;
+let mut closure = move || { foo = 2; };
+closure();
+dbg!(foo); // foo is still 1, but the copy of `foo` in `closure` is 2
+```
+
+Note that `foo` is _copied_ during move in this example
+as `i32` implements `Copy`.
+
+If a closure captures multiple bindings,
+the `move` keyword makes them all captured by moving.
+To only indicate this for specific bindings,
+list them in parentheses after `move`:
+
+```rs
+let foo = 1;
+let mut bar = 2;
+let mut closure = move(mut foo) || {
+ foo += 10;
+ bar += 10;
+};
+closure();
+dbg!(foo, bar); // foo = 1, bar = 12
+```
+
+Note that the outer `foo` no longer requires `mut`;
+it is relocated to the closure since it defines a new binding.
+Meanwhile, `bar` continues to capture by usage (i.e. by reference).
+
+Moved bindings may also be renamed:
+
+```rs
+let mut foo = 1;
+let mut closure = move(mut bar = foo) || {
+ foo = 2;
+ bar = 3;
+};
+closure();
+dbg!(foo); // the outer `foo` is 2 as it was captured by reference
+```
+
+Bindings may be transformed when moved:
+
+```rs
+let foo = vec![1];
+let mut closure = move(mut foo = foo.clone()) || {
+ foo.push(2);
+};
+closure();
+dbg!(foo); // the outer `foo` is still [1] because only the cloned copy was mutated
+```
+
+# Reference-level explanation
+[reference-level-explanation]: #reference-level-explanation
+
+A closure expression has the following syntax:
+
+> **Syntax**\
+> _ClosureExpression_ :\
+> ( `move` _MoveBindings_? )?\
+> ( `||` | `|` _ClosureParameters_? `|` )\
+> (_Expression_ | `->` _TypeNoBounds_ _BlockExpression_)>\
+> _MoveBindings_ :\
+> `(` ( _MoveBinding_ (`,` _MoveBinding_)\* `,`? )? `)`\
+> _MoveBinding_ :\
+> _NamedMoveBinding_ | _UnnamedMoveBinding_\
+> _NamedMoveBinding_ :\
+> _PatternNoTopAlt_ `=` _Expression_\
+> _UnnamedMoveBinding_ :\
+> `mut`? _IdentifierExpression_ \
+> _ClosureParameters_ :\
+> _ClosureParam_ (`,` _ClosureParam_)\* `,`?\
+> _ClosureParam_ :\
+> _OuterAttribute_\* _PatternNoTopAlt_ ( `:` _Type_ )?
+
+Closure expressions are classified into two main types,
+namely _ByUsage_ and _FullMove_.
+A closure expression is _FullMove_ IF AND ONLY IF
+it starts with a `move` token immediately followed by a `|` token,
+without any parentheses in between.
+
+## _ByUsage_ closures
+
+When the parentheses for _MoveBindings_ is present,
+or when the `move` keyword is absent,
+the closure expression is of the _ByUsage_ type, where
+all local variables in the closure construction scope not shadowed by any _MoveBinding_
+are implicitly captured into the closure
+by shared reference, mutable reference or move on demand,
+preferring the first possible type.
+
+Each _MoveBinding_ declares binding(s) in its left-side pattern,
+assigned with the value of the right-side expression evaluated during closure construction,
+thus referencing any relevant local variables if necessary.
+
+If the left-side pattern is omitted (_UnnamedMoveBinding_),
+the expression must be a single-segment (identifier) `PathExpression`.
+The left-side pattern is then automatically inferred to be a _IdentifierPattern_
+using the identifier as the new binding.
+
+### Mutable bindings
+
+If a captured binding mutated inside the closure is declared in a _NamedMoveBinding_,
+the `IdentifierPattern` that declares the binding must have the `mut` keyword.
+
+If it is declared in an _UnnamedMoveBinding_,
+the `mut` keyword must be added in front of the expression;
+since the declared binding is always the first token in the expression,
+the `mut` token is always immediately followed by the mutable binding,
+thus yielding consistent readability.
+
+If it is implicitly captured from the parent scope
+instead of declared in a _MoveBinding_,
+the local variable declaration must be declared `mut` too.
+
+## _FullMove_ closures
+
+When the `move` keyword is present but _MoveBindings_ is absent (with its parentheses absent as well),
+the closure expression is of the _FullMove_ type, where
+all local variables in the closure construction scope
+are implicitly moved or copied into the closure on demand.
+
+Note that `move` with an empty pair of parentheses is allowed and follows the former rule;
+in other words, `move() |...| {...}` and `|...| {...}` are semantically equivalent.
+This allows macros to emit repeating groups of `_MoveBinding_ ","` inside a pair of parentheses
+and achieve correct semantics when there are zero repeating groups.
+
+If a moved binding is mutated inside the closure,
+its declaration in the parent scope must be declared `mut` too.
+
+# Drawbacks
+[drawbacks]: #drawbacks
+
+Due to backwards compatibility, this RFC proposes a new syntax
+that is an extension of capture-by-move
+but actually looks more similar to capture-by-reference,
+thus confusing new users.
+
+# Rationale and alternatives
+[rationale-and-alternatives]: #rationale-and-alternatives
+
+Capture-by-reference is the default behavior for implicit captures for two reasons:
+
+1. It is more consistent to have `move(x)` imply `move(x=x)`,
+which leaves us with implicit references for the unspecified.
+2. Move bindings actually define a new shadowing binding
+that is completely independent of the original binding,
+so it is more correct to have the new binding explicitly named.
+Consider how unintuitive it is to require that
+a moved variable be declared `mut` in the outer scope
+even though it is only mutated inside the closure (as the new binding).
+
+The possible syntax for automatically-inferred _MoveBinding_ pattern
+is strictly limited to allow maximum future compatibility.
+Currently, many cases of captured bindings are in the form of
+`foo = foo`, `foo = &foo` or `foo.clone()`.
+This RFC intends to solve the ergonomic issues for these common scenarios first
+and leave more room for future enhancement when other frequent patterns are identified.
+
+Alternative approaches previously proposed
+include explicitly adding support for the `clone` keyword.
+This RFC does not favor such suggestions
+as they make the fundamental closure expression syntax
+unnecessarily dependent on the `clone` language item,
+and does not offer possibilities for alternative transformers.
+
+## `move` inside parameter list
+
+As an alternative to having `move(binding)` ahead of a closure, we could put `move binding` in the parameter list: `|x: T, move y, move z = z.clone()| { ... }`.
+
+This would have the advantage of keeping the list of declared names in one place, and giving a view of closures as having some bindings passed in as arguments and other bindings captured from the containing scope.
+
+However, this would have the disadvantage of visually looking like the caller could pass the value in as a parameter, which it cannot.
+# Prior art
+[prior-art]: #prior-art
+
+## Other languages
+
+Closure expressions (with the ability to capture) are known to many languages,
+varying between explicit and implicit capturing.
+Nevertheless, most such languages do not support capturing by reference.
+Examples of languages that support capture-by-reference include
+C++ lambdas (`[x=f(y)]`) and PHP (`use(&$x)`).
+Of these, C++ uses a leading `&`/`=` in the capture list
+to indicate the default behavior as move or reference,
+and allows an initializer behind a variable:
+
+```cpp
+int foo = 1;
+auto closure = [foo = foo+1]() mutable {
+ foo += 10; // does not mutate ::foo
+ return foo;
+}
+closure(); // 12
+closure(); // 22
+```
+
+This RFC additionally proposes the ability to omit the capture identifier,
+because use cases of `foo.clone()` are much more common in Rust,
+compared to C++ where most values may be implicitly cloned.
+
+## Rust libraries
+
+Attempts to improve ergonomics for cloning into closures were seen in proc macros:
+
+- [enclose](https://crates.io/crates/enclose)
+- [clown](https://crates.io/crates/clown)
+- [closet](https://crates.io/crates/closet)
+- [capture](https://crates.io/crates/capture)
+
+# Unresolved questions
+[unresolved-questions]: #unresolved-questions
+
+- This RFC actually solves two not necessarily related problems together,
+namely clone-into-closures and selective capture-by-move.
+It might be more appropriate to split the former to a separate RFC,
+but they are currently put together such that
+consideration for the new syntax includes possibility for both enhancements.
+
+# Future possibilities
+[future-possibilities]: #future-possibilities
+
+- Should we consider deprecating the _FullMove_ syntax
+in favor of explicitly specifying what gets moved,
+especially for mutable variables,
+considering that moved variables actually create a new, shadowing binding?
+- The set of allowed expressions may be extended in the future.