about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-31 23:45:37 +0000
committerbors <bors@rust-lang.org>2021-01-31 23:45:37 +0000
commit941343e0871dd04ea774e8cee7755461b144ef29 (patch)
treef1b0d9272f0e8021ea13bb21054700ce52406c2f
parent0e63af5da3400ace48a0345117980473fd21ad73 (diff)
parent9165676d91d3e458a57f4f4eacc3975d89be9f5a (diff)
downloadrust-941343e0871dd04ea774e8cee7755461b144ef29.tar.gz
rust-941343e0871dd04ea774e8cee7755461b144ef29.zip
Auto merge of #81596 - jonas-schievink:rollup-utk14gr, r=jonas-schievink
Rollup of 11 pull requests

Successful merges:

 - #80092 (2229: Fix issues with move closures and mutability)
 - #80404 (Remove const_in_array_repeat)
 - #81255 (Don't link with --export-dynamic on wasm32-wasi)
 - #81480 (Add suggestion for nested fields)
 - #81549 (Misc ip documentation fixes)
 - #81566 (Add a test for #71202)
 - #81568 (Fix an old FIXME in redundant paren lint)
 - #81571 (Fix typo in E0759)
 - #81572 (Edit multiple error code Markdown files)
 - #81589 (Fix small typo in string.rs)
 - #81590 (Stabilize int_bits_const)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0013.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0038.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0107.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0116.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0277.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0309.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0597.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0658.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0754.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0759.md2
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs19
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs4
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs32
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs7
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs74
-rw-r--r--compiler/rustc_mir/src/borrow_check/nll.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/path_utils.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs23
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs66
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs11
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/tests/leb128.rs1
-rw-r--r--compiler/rustc_target/src/spec/wasm32_base.rs9
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs13
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs15
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs120
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs131
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/core/src/num/int_macros.rs3
-rw-r--r--library/core/src/num/uint_macros.rs3
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/panic_unwind/src/lib.rs1
-rw-r--r--library/std/src/net/ip.rs14
-rw-r--r--src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md11
-rw-r--r--src/test/ui/array-slice-vec/repeat_empty_ok.rs15
-rw-r--r--src/test/ui/array-slice-vec/repeat_empty_ok.stderr19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/by_value.rs41
-rw-r--r--src/test/ui/closures/2229_closure_analysis/by_value.stderr67
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs20
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs35
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr30
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs38
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr33
-rw-r--r--src/test/ui/closures/2229_closure_analysis/move_closure.rs72
-rw-r--r--src/test/ui/closures/2229_closure_analysis/move_closure.stderr147
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs64
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs56
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs45
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs47
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs63
-rw-r--r--src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr102
-rw-r--r--src/test/ui/const-generics/issue-71202.rs33
-rw-r--r--src/test/ui/consts/const-blocks/const-repeat.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs)0
-rw-r--r--src/test/ui/consts/const-blocks/fn-call-in-const.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs)6
-rw-r--r--src/test/ui/consts/const-blocks/fn-call-in-non-const.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs)2
-rw-r--r--src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr)2
-rw-r--r--src/test/ui/consts/const-blocks/migrate-fail.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs)1
-rw-r--r--src/test/ui/consts/const-blocks/migrate-fail.stderr (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr)4
-rw-r--r--src/test/ui/consts/const-blocks/migrate-pass.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs)1
-rw-r--r--src/test/ui/consts/const-blocks/nll-fail.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs)1
-rw-r--r--src/test/ui/consts/const-blocks/nll-fail.stderr (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr)4
-rw-r--r--src/test/ui/consts/const-blocks/nll-pass.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs)1
-rw-r--r--src/test/ui/consts/const-blocks/run-pass.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs)1
-rw-r--r--src/test/ui/consts/const-blocks/trait-error.rs (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs)2
-rw-r--r--src/test/ui/consts/const-blocks/trait-error.stderr (renamed from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr)2
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs17
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr25
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs43
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr11
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed42
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield.rs42
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr27
-rw-r--r--src/test/ui/unused/unused-closure.rs5
-rw-r--r--src/test/ui/unused/unused-closure.stderr28
90 files changed, 1599 insertions, 326 deletions
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 5880bbd3de4..36d261fb737 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(unboxed_closures)]
 #![feature(generator_trait)]
 #![feature(fn_traits)]
-#![feature(int_bits_const)]
 #![feature(min_specialization)]
 #![feature(auto_traits)]
 #![feature(nll)]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md
index 8de177590ec..5605302772f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0013.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0013.md
@@ -8,7 +8,7 @@ static X: i32 = 42;
 const Y: i32 = X;
 ```
 
-In this example, `Y` cannot refer to `X` here. To fix this, the value can be
+In this example, `Y` cannot refer to `X`. To fix this, the value can be
 extracted as a const and then used:
 
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index b2cc2a2273a..019d54b6202 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -287,5 +287,5 @@ the method `get_a()` would return an object of unknown type when called on the
 function. `Self` type parameters let us make object safe traits no longer safe,
 so they are forbidden when specifying supertraits.
 
-There's no easy fix for this, generally code will need to be refactored so that
+There's no easy fix for this. Generally, code will need to be refactored so that
 you no longer need to derive from `Super<Self>`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0107.md b/compiler/rustc_error_codes/src/error_codes/E0107.md
index 4d22b17fe10..4e37695a529 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0107.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0107.md
@@ -1,4 +1,4 @@
-An incorrect number of generic arguments were provided.
+An incorrect number of generic arguments was provided.
 
 Erroneous code example:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0116.md b/compiler/rustc_error_codes/src/error_codes/E0116.md
index ca849c2a128..653be602989 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0116.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0116.md
@@ -10,7 +10,7 @@ You can only define an inherent implementation for a type in the same crate
 where the type was defined. For example, an `impl` block as above is not allowed
 since `Vec` is defined in the standard library.
 
-To fix this problem, you can do either of these things:
+To fix this problem, you can either:
 
  - define a trait that has the desired associated functions/types/constants and
    implement the trait for the type in question
diff --git a/compiler/rustc_error_codes/src/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md
index 2e2cd5e01fb..9f6db6ed7a2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0277.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0277.md
@@ -59,9 +59,9 @@ fn main() {
 }
 ```
 
-Note that the error here is in the definition of the generic function: Although
+Note that the error here is in the definition of the generic function. Although
 we only call it with a parameter that does implement `Debug`, the compiler
-still rejects the function: It must work with all possible input types. In
+still rejects the function. It must work with all possible input types. In
 order to make this example compile, we need to restrict the generic type we're
 accepting:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0309.md b/compiler/rustc_error_codes/src/error_codes/E0309.md
index e719ee590ab..c36a56b00ce 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0309.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0309.md
@@ -25,7 +25,7 @@ where
 
 The type definition contains some field whose type requires an outlives
 annotation. Outlives annotations (e.g., `T: 'a`) are used to guarantee that all
-the data in T is valid for at least the lifetime `'a`. This scenario most
+the data in `T` is valid for at least the lifetime `'a`. This scenario most
 commonly arises when the type contains an associated type reference like
 `<T as SomeTrait<'a>>::Output`, as shown in the previous code.
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0597.md b/compiler/rustc_error_codes/src/error_codes/E0597.md
index 3340768fa82..f6e0b62e1b6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0597.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0597.md
@@ -1,4 +1,4 @@
-This error occurs because a value was dropped while it was still borrowed
+This error occurs because a value was dropped while it was still borrowed.
 
 Erroneous code example:
 
@@ -15,7 +15,7 @@ let mut x = Foo { x: None };
 println!("{:?}", x.x);
 ```
 
-In here, `y` is dropped at the end of the inner scope, but it is borrowed by
+Here, `y` is dropped at the end of the inner scope, but it is borrowed by
 `x` until the `println`. To fix the previous example, just remove the scope
 so that `y` isn't dropped until after the println
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md
index d821b9027f1..24245a38ae0 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0658.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0658.md
@@ -11,7 +11,7 @@ enum Foo {
 
 If you're using a stable or a beta version of rustc, you won't be able to use
 any unstable features. In order to do so, please switch to a nightly version of
-rustc (by using rustup).
+rustc (by using [rustup]).
 
 If you're using a nightly version of rustc, just add the corresponding feature
 to be able to use it:
@@ -24,3 +24,5 @@ enum Foo {
     Bar(u64),
 }
 ```
+
+[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0754.md b/compiler/rustc_error_codes/src/error_codes/E0754.md
index 57620bcd65c..9f4b19cfda6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0754.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0754.md
@@ -1,4 +1,4 @@
-An non-ascii identifier was used in an invalid context.
+A non-ASCII identifier was used in an invalid context.
 
 Erroneous code examples:
 
@@ -13,7 +13,7 @@ fn řųśť() {} // error!
 fn main() {}
 ```
 
-Non-ascii can be used as module names if it is inlined or if a `#[path]`
+Non-ASCII can be used as module names if it is inlined or if a `#[path]`
 attribute is specified. For example:
 
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md
index 6d525310f75..2fe5ada257f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0759.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0759.md
@@ -27,7 +27,7 @@ fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok!
 }
 ```
 
-Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
+Both [`dyn Trait`] and [`impl Trait`] in return types have an implicit
 `'static` requirement, meaning that the value implementing them that is being
 returned has to be either a `'static` borrow or an owned value.
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index cd3c8fded63..e12b533b110 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -485,9 +485,6 @@ declare_features! (
     /// Allows `async || body` closures.
     (active, async_closure, "1.37.0", Some(62290), None),
 
-    /// Allows `[x; N]` where `x` is a constant (RFC 2203).
-    (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None),
-
     /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
     (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
 
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 07bd1602cda..38a3a4e3d44 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -97,6 +97,9 @@ declare_features! (
     (removed, extern_in_paths, "1.33.0", Some(55600), None,
      Some("subsumed by `::foo::bar` paths")),
     (removed, quote, "1.33.0", Some(29601), None, None),
+    /// Allows `[x; N]` where `x` is a constant (RFC 2203).
+    (removed, const_in_array_repeat_expressions,  "1.37.0", Some(49147), None,
+     Some("removed due to causing promotable bugs")),
     /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
     (removed, dropck_parametricity, "1.38.0", Some(28498), None, None),
     (removed, await_macro, "1.38.0", Some(50547), None,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index c1a3eecbbc7..b611aebad01 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -977,8 +977,6 @@ impl UnusedDelimLint for UnusedBraces {
                 }
             }
             ast::ExprKind::Let(_, ref expr) => {
-                // FIXME(#60336): Properly handle `let true = (false && true)`
-                // actually needing the parenthesis.
                 self.check_unused_delims_expr(
                     cx,
                     expr,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 0a663f793aa..163b400973b 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -228,8 +228,7 @@ pub enum ObligationCauseCode<'tcx> {
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
     /// `[T, ..n]` implies that `T` must be `Copy`.
-    /// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
-    RepeatVec(bool),
+    RepeatVec,
 
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8e8caa46c38..babab005edb 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -661,11 +661,28 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureLis
 /// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
 pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
 
-/// A `Place` and the corresponding `CaptureInfo`.
+/// A composite describing a `Place` that is captured by a closure.
 #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
 pub struct CapturedPlace<'tcx> {
+    /// The `Place` that is captured.
     pub place: HirPlace<'tcx>,
+
+    /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
     pub info: CaptureInfo<'tcx>,
+
+    /// Represents if `place` can be mutated or not.
+    pub mutability: hir::Mutability,
+}
+
+impl CapturedPlace<'tcx> {
+    /// Returns the hir-id of the root variable for the captured place.
+    /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
+    pub fn get_root_variable(&self) -> hir::HirId {
+        match self.place.base {
+            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+            base => bug!("Expected upvar, found={:?}", base),
+        }
+    }
 }
 
 pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 6d98bf554f1..04ea3cbd8b6 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -215,6 +215,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
+                        // FIXME(project-rfc_2229#36): print capture precisely here.
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
@@ -259,6 +260,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     ProjectionElem::Field(field, _ty) => {
                         autoderef = true;
 
+                        // FIXME(project-rfc_2229#36): print capture precisely here.
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
index 350e0d045fa..fb7694b7d88 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -345,7 +345,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
 
                 let upvar = &self.upvars[upvar_field.unwrap().index()];
-                let upvar_hir_id = upvar.var_hir_id;
+                // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise
+                //                            capture.
+                let upvar_hir_id = upvar.place.get_root_variable();
                 let upvar_name = upvar.name;
                 let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
 
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 73196c732f5..74abe2d35ee 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -64,12 +64,29 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
-                item_msg = format!("`{}`", access_place_desc.unwrap());
-                if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
-                    reason = ", as it is not declared as mutable".to_string();
+                let imm_borrow_derefed = self.upvars[upvar_index.index()]
+                    .place
+                    .place
+                    .deref_tys()
+                    .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)));
+
+                // If the place is immutable then:
+                //
+                // - Either we deref a immutable ref to get to our final place.
+                //    - We don't capture derefs of raw ptrs
+                // - Or the final place is immut because the root variable of the capture
+                //   isn't marked mut and we should suggest that to the user.
+                if imm_borrow_derefed {
+                    // If we deref an immutable ref then the suggestion here doesn't help.
+                    return;
                 } else {
-                    let name = self.upvars[upvar_index.index()].name;
-                    reason = format!(", as `{}` is not declared as mutable", name);
+                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
+                        reason = ", as it is not declared as mutable".to_string();
+                    } else {
+                        let name = self.upvars[upvar_index.index()].name;
+                        reason = format!(", as `{}` is not declared as mutable", name);
+                    }
                 }
             }
 
@@ -259,9 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
+                let captured_place = &self.upvars[upvar_index.index()].place;
+
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
-                let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id;
+                let upvar_hir_id = captured_place.get_root_variable();
+
                 if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) {
                     if let hir::PatKind::Binding(
                         hir::BindingAnnotation::Unannotated,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
index a850b85e9bb..4abc623fc5f 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
@@ -12,7 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         local_names: &IndexVec<Local, Option<Symbol>>,
-        upvars: &[Upvar],
+        upvars: &[Upvar<'tcx>],
         fr: RegionVid,
     ) -> Option<(Option<Symbol>, Span)> {
         debug!("get_var_name_and_span_for_region(fr={:?})", fr);
@@ -21,6 +21,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("get_var_name_and_span_for_region: attempting upvar");
         self.get_upvar_index_for_region(tcx, fr)
             .map(|index| {
+                // FIXME(project-rfc-2229#8): Use place span for diagnostics
                 let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index);
                 (Some(name), span)
             })
@@ -59,10 +60,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     crate fn get_upvar_name_and_span_for_region(
         &self,
         tcx: TyCtxt<'tcx>,
-        upvars: &[Upvar],
+        upvars: &[Upvar<'tcx>],
         upvar_index: usize,
     ) -> (Symbol, Span) {
-        let upvar_hir_id = upvars[upvar_index].var_hir_id;
+        let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
         debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
 
         let upvar_name = tcx.hir().name(upvar_hir_id);
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 7c7edfdb5fb..5db52db70ac 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -5,11 +5,10 @@ use rustc_data_structures::graph::dominators::Dominators;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{HirId, Node};
+use rustc_hir::Node;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::mir::{
     traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
     PlaceRef, VarDebugInfoContents,
@@ -18,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
@@ -73,16 +72,14 @@ crate use region_infer::RegionInferenceContext;
 
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
-crate struct Upvar {
+crate struct Upvar<'tcx> {
+    // FIXME(project-rfc_2229#36): print capture precisely here.
     name: Symbol,
 
-    // FIXME(project-rfc-2229#8): This should use Place or something similar
-    var_hir_id: HirId,
+    place: CapturedPlace<'tcx>,
 
     /// If true, the capture is behind a reference.
     by_ref: bool,
-
-    mutability: Mutability,
 }
 
 const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
@@ -161,26 +158,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     let upvars: Vec<_> = tables
         .closure_min_captures_flattened(def.did.to_def_id())
         .map(|captured_place| {
-            let var_hir_id = match captured_place.place.base {
-                HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
-                _ => bug!("Expected upvar"),
-            };
+            let var_hir_id = captured_place.get_root_variable();
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
                 ty::UpvarCapture::ByValue(_) => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
-            let mut upvar = Upvar {
-                name: tcx.hir().name(var_hir_id),
-                var_hir_id,
-                by_ref,
-                mutability: Mutability::Not,
-            };
-            let bm = *tables.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
-            if bm == ty::BindByValue(hir::Mutability::Mut) {
-                upvar.mutability = Mutability::Mut;
-            }
-            upvar
+            Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref }
         })
         .collect();
 
@@ -549,7 +533,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
     dominators: Dominators<BasicBlock>,
 
     /// Information about upvars not necessarily preserved in types or MIR
-    upvars: Vec<Upvar>,
+    upvars: Vec<Upvar<'tcx>>,
 
     /// Names of local (user) variables (extracted from `var_debug_info`).
     local_names: IndexVec<Local, Option<Symbol>>,
@@ -1374,13 +1358,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
-            if !place.projection.is_empty() {
-                if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
+            // We have three possibilities here:
+            // a. We are modifying something through a mut-ref
+            // b. We are modifying something that is local to our parent
+            // c. Current body is a nested closure, and we are modifying path starting from
+            //    a Place captured by our parent closure.
+
+            // Handle (c), the path being modified is exactly the path captured by our parent
+            if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
+                this.used_mut_upvars.push(field);
+                return;
+            }
+
+            for (place_ref, proj) in place.iter_projections().rev() {
+                // Handle (a)
+                if proj == ProjectionElem::Deref {
+                    match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
+                        // We aren't modifying a variable directly
+                        ty::Ref(_, _, hir::Mutability::Mut) => return,
+
+                        _ => {}
+                    }
+                }
+
+                // Handle (c)
+                if let Some(field) = this.is_upvar_field_projection(place_ref) {
                     this.used_mut_upvars.push(field);
+                    return;
                 }
-            } else {
-                this.used_mut.insert(place.local);
             }
+
+            // Handle(b)
+            this.used_mut.insert(place.local);
         };
 
         // This relies on the current way that by-value
@@ -2146,6 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         place: PlaceRef<'tcx>,
         is_local_mutation_allowed: LocalMutationIsAllowed,
     ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
+        debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
         match place.last_projection() {
             None => {
                 let local = &self.body.local_decls[place.local];
@@ -2227,11 +2237,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         if let Some(field) = upvar_field_projection {
                             let upvar = &self.upvars[field.index()];
                             debug!(
-                                "upvar.mutability={:?} local_mutation_is_allowed={:?} \
-                                 place={:?}",
-                                upvar, is_local_mutation_allowed, place
+                                "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
+                                 place={:?}, place_base={:?}",
+                                upvar, is_local_mutation_allowed, place, place_base
                             );
-                            match (upvar.mutability, is_local_mutation_allowed) {
+                            match (upvar.place.mutability, is_local_mutation_allowed) {
                                 (
                                     Mutability::Not,
                                     LocalMutationIsAllowed::No
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs
index 359c5f261a4..a0265b20d12 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_mir/src/borrow_check/nll.rs
@@ -165,7 +165,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    upvars: &[Upvar],
+    upvars: &[Upvar<'tcx>],
 ) -> NllOutput<'tcx> {
     let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
 
diff --git a/compiler/rustc_mir/src/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs
index fa3ae2367e0..80de3b4e363 100644
--- a/compiler/rustc_mir/src/borrow_check/path_utils.rs
+++ b/compiler/rustc_mir/src/borrow_check/path_utils.rs
@@ -143,7 +143,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
 /// of a closure type.
 pub(crate) fn is_upvar_field_projection(
     tcx: TyCtxt<'tcx>,
-    upvars: &[Upvar],
+    upvars: &[Upvar<'tcx>],
     place_ref: PlaceRef<'tcx>,
     body: &Body<'tcx>,
 ) -> Option<Field> {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index fb9820e853f..e689964b998 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -43,10 +43,6 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}
 use crate::dataflow::impls::MaybeInitializedPlaces;
 use crate::dataflow::move_paths::MoveData;
 use crate::dataflow::ResultsCursor;
-use crate::transform::{
-    check_consts::ConstCx,
-    promote_consts::should_suggest_const_in_array_repeat_expressions_attribute,
-};
 
 use crate::borrow_check::{
     borrow_set::BorrowSet,
@@ -132,7 +128,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     elements: &Rc<RegionValueElements>,
-    upvars: &[Upvar],
+    upvars: &[Upvar<'tcx>],
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
     let mut constraints = MirTypeckRegionConstraints {
@@ -821,7 +817,7 @@ struct BorrowCheckContext<'a, 'tcx> {
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
-    upvars: &'a [Upvar],
+    upvars: &'a [Upvar<'tcx>],
 }
 
 crate struct MirTypeckResults<'tcx> {
@@ -1997,22 +1993,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             let span = body.source_info(location).span;
                             let ty = operand.ty(body, tcx);
                             if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
-                                let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
-                                // To determine if `const_in_array_repeat_expressions` feature gate should
-                                // be mentioned, need to check if the rvalue is promotable.
-                                let should_suggest =
-                                    should_suggest_const_in_array_repeat_expressions_attribute(
-                                        &ccx, operand,
-                                    );
-                                debug!("check_rvalue: should_suggest={:?}", should_suggest);
-
                                 let def_id = body.source.def_id().expect_local();
                                 self.infcx.report_selection_error(
                                     &traits::Obligation::new(
                                         ObligationCause::new(
                                             span,
                                             self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                            traits::ObligationCauseCode::RepeatVec(should_suggest),
+                                            traits::ObligationCauseCode::RepeatVec,
                                         ),
                                         self.param_env,
                                         ty::Binder::bind(ty::TraitRef::new(
@@ -2490,7 +2477,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             body,
         );
         let category = if let Some(field) = field {
-            ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id)
+            let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable();
+            // FIXME(project-rfc-2229#8): Use Place for better diagnostics
+            ConstraintCategory::ClosureUpvar(var_hir_id)
         } else {
             ConstraintCategory::Boring
         };
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index d8758e04544..b4504a0e223 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -102,9 +102,6 @@ pub enum Candidate {
     /// Borrow of a constant temporary, candidate for lifetime extension.
     Ref(Location),
 
-    /// Promotion of the `x` in `[x; 32]`.
-    Repeat(Location),
-
     /// Currently applied to function calls where the callee has the unstable
     /// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
     /// intrinsic. The intrinsic requires the arguments are indeed constant and
@@ -120,14 +117,14 @@ impl Candidate {
     /// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
     fn forces_explicit_promotion(&self) -> bool {
         match self {
-            Candidate::Ref(_) | Candidate::Repeat(_) => false,
+            Candidate::Ref(_) => false,
             Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true,
         }
     }
 
     fn source_info(&self, body: &Body<'_>) -> SourceInfo {
         match self {
-            Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location),
+            Candidate::Ref(location) => *body.source_info(*location),
             Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => {
                 *body.source_info(body.terminator_loc(*bb))
             }
@@ -213,11 +210,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
             Rvalue::Ref(..) => {
                 self.candidates.push(Candidate::Ref(location));
             }
-            Rvalue::Repeat(..) if self.ccx.tcx.features().const_in_array_repeat_expressions => {
-                // FIXME(#49147) only promote the element when it isn't `Copy`
-                // (so that code that can copy it at runtime is unaffected).
-                self.candidates.push(Candidate::Repeat(location));
-            }
             _ => {}
         }
     }
@@ -334,21 +326,6 @@ impl<'tcx> Validator<'_, 'tcx> {
                     _ => bug!(),
                 }
             }
-            Candidate::Repeat(loc) => {
-                assert!(!self.explicit);
-
-                let statement = &self.body[loc.block].statements[loc.statement_index];
-                match &statement.kind {
-                    StatementKind::Assign(box (_, Rvalue::Repeat(ref operand, _))) => {
-                        if !self.tcx.features().const_in_array_repeat_expressions {
-                            return Err(Unpromotable);
-                        }
-
-                        self.validate_operand(operand)
-                    }
-                    _ => bug!(),
-                }
-            }
             Candidate::Argument { bb, index } => {
                 assert!(self.explicit);
 
@@ -1090,18 +1067,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         _ => bug!(),
                     }
                 }
-                Candidate::Repeat(loc) => {
-                    let statement = &mut blocks[loc.block].statements[loc.statement_index];
-                    match statement.kind {
-                        StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
-                            let ty = operand.ty(local_decls, self.tcx);
-                            let span = statement.source_info.span;
-
-                            Rvalue::Use(mem::replace(operand, promoted_operand(ty, span)))
-                        }
-                        _ => bug!(),
-                    }
-                }
                 Candidate::Argument { bb, index } => {
                     let terminator = blocks[bb].terminator_mut();
                     match terminator.kind {
@@ -1182,8 +1147,7 @@ pub fn promote_candidates<'tcx>(
     let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
         match candidate {
-            Candidate::Repeat(Location { block, statement_index })
-            | Candidate::Ref(Location { block, statement_index }) => {
+            Candidate::Ref(Location { block, statement_index }) => {
                 if let StatementKind::Assign(box (place, _)) =
                     &body[block].statements[statement_index].kind
                 {
@@ -1267,27 +1231,3 @@ pub fn promote_candidates<'tcx>(
 
     promotions
 }
-
-/// This function returns `true` if the `const_in_array_repeat_expressions` feature attribute should
-/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path.
-/// Feature attribute should be suggested if `operand` can be promoted and the feature is not
-/// enabled.
-crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
-    ccx: &ConstCx<'_, 'tcx>,
-    operand: &Operand<'tcx>,
-) -> bool {
-    let mut rpo = traversal::reverse_postorder(&ccx.body);
-    let (temps, _) = collect_temps_and_candidates(&ccx, &mut rpo);
-    let validator = Validator { ccx, temps: &temps, explicit: false };
-
-    let should_promote = validator.validate_operand(operand).is_ok();
-    let feature_flag = validator.ccx.tcx.features().const_in_array_repeat_expressions;
-    debug!(
-        "should_suggest_const_in_array_repeat_expressions_flag: def_id={:?} \
-            should_promote={:?} feature_flag={:?}",
-        validator.ccx.def_id(),
-        should_promote,
-        feature_flag
-    );
-    should_promote && !feature_flag
-}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 99661599525..e4891eb5a3c 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -851,22 +851,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         _ => bug!("Expected an upvar")
                     };
 
-                    let mut mutability = Mutability::Not;
+                    let mutability = captured_place.mutability;
 
                     // FIXME(project-rfc-2229#8): Store more precise information
                     let mut name = kw::Empty;
                     if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
                         if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
                             name = ident.name;
-                            match hir_typeck_results
-                                .extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
-                            {
-                                Some(ty::BindByValue(hir::Mutability::Mut)) => {
-                                    mutability = Mutability::Mut;
-                                }
-                                Some(_) => mutability = Mutability::Not,
-                                _ => {}
-                            }
                         }
                     }
 
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 53c3adcc20c..ea04e7bb44b 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -17,7 +17,6 @@ Core encoding and decoding interfaces.
 #![feature(min_specialization)]
 #![feature(vec_spare_capacity)]
 #![feature(core_intrinsics)]
-#![feature(int_bits_const)]
 #![feature(maybe_uninit_slice)]
 #![feature(new_uninit)]
 #![cfg_attr(test, feature(test))]
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index a2bcf2c251d..3e2aab5125a 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -1,4 +1,3 @@
-#![feature(int_bits_const)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 
diff --git a/compiler/rustc_target/src/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs
index a7957d84cbe..bfef3d37228 100644
--- a/compiler/rustc_target/src/spec/wasm32_base.rs
+++ b/compiler/rustc_target/src/spec/wasm32_base.rs
@@ -55,15 +55,6 @@ pub fn options() -> TargetOptions {
     // to do so.
     arg("--no-demangle");
 
-    // The symbol visibility story is a bit in flux right now with LLD.
-    // It's... not entirely clear to me what's going on, but this looks to
-    // make everything work when `export_symbols` isn't otherwise called for
-    // things like executables.
-    //
-    // This is really only here to get things working. If it can be removed and
-    // basic tests still work, then sounds like it should be removed!
-    arg("--export-dynamic");
-
     let mut pre_link_args = BTreeMap::new();
     pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
     pre_link_args.insert(LinkerFlavor::Gcc, clang_args);
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index c12757b8f98..9f69ce16c21 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -2,6 +2,17 @@ use super::wasm32_base;
 use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let mut options = wasm32_base::options();
+
+    let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+
+    // Rust really needs a way for users to specify exports and imports in
+    // the source code. --export-dynamic isn't the right tool for this job,
+    // however it does have the side effect of automatically exporting a lot
+    // of symbols, which approximates what people want when compiling for
+    // wasm32-unknown-unknown expect, so use it for now.
+    clang_args.push("--export-dynamic".to_string());
+
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(
         LinkerFlavor::Em,
@@ -28,7 +39,7 @@ pub fn target() -> Target {
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
         os_family: Some("unix".to_string()),
-        ..wasm32_base::options()
+        ..options
     };
     Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 6037aa5b430..5e89ba2520b 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -26,11 +26,18 @@ pub fn target() -> Target {
     // For now this target just never has an entry symbol no matter the output
     // type, so unconditionally pass this.
     clang_args.push("-Wl,--no-entry".to_string());
-    options
-        .pre_link_args
-        .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm))
-        .unwrap()
-        .push("--no-entry".to_string());
+
+    // Rust really needs a way for users to specify exports and imports in
+    // the source code. --export-dynamic isn't the right tool for this job,
+    // however it does have the side effect of automatically exporting a lot
+    // of symbols, which approximates what people want when compiling for
+    // wasm32-unknown-unknown expect, so use it for now.
+    clang_args.push("-Wl,--export-dynamic".to_string());
+
+    // Add the flags to wasm-ld's args too.
+    let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap();
+    lld_args.push("--no-entry".to_string());
+    lld_args.push("--export-dynamic".to_string());
 
     Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 0724a9290e9..690591930de 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1881,23 +1881,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::Coercion { source: _, target } => {
                 err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
             }
-            ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
+            ObligationCauseCode::RepeatVec => {
                 err.note(
                     "the `Copy` trait is required because the repeated element will be copied",
                 );
-                if suggest_const_in_array_repeat_expressions {
-                    err.note(
-                        "this array initializer can be evaluated at compile-time, see issue \
-                         #49147 <https://github.com/rust-lang/rust/issues/49147> \
-                         for more information",
-                    );
-                    if tcx.sess.opts.unstable_features.is_nightly_build() {
-                        err.help(
-                            "add `#![feature(const_in_array_repeat_expressions)]` to the \
-                             crate attributes to enable",
-                        );
-                    }
-                }
             }
             ObligationCauseCode::VariableType(hir_id) => {
                 let parent_node = self.tcx.hir().get_parent_node(hir_id);
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index e37b4ff742b..04c83a7665c 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -36,6 +36,7 @@ use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{AdtKind, Visibility};
@@ -46,8 +47,6 @@ use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
-use std::fmt::Display;
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) {
         let ty = self.check_expr_with_hint(expr, expected);
@@ -1585,11 +1584,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base: &'tcx hir::Expr<'tcx>,
         field: Ident,
     ) -> Ty<'tcx> {
+        debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
         let expr_t = self.check_expr(base);
         let expr_t = self.structurally_resolved_type(base.span, expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, _)) = autoderef.next() {
+            debug!("base_t: {:?}", base_t);
             match base_t.kind() {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
                     debug!("struct named {:?}", base_t);
@@ -1706,7 +1707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
             field, base, expr, expr_t
         );
-        let mut err = self.no_such_field_err(field.span, field, expr_t);
+        let mut err = self.no_such_field_err(field, expr_t);
 
         match *expr_t.peel_refs().kind() {
             ty::Array(_, len) => {
@@ -1880,21 +1881,120 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn no_such_field_err<T: Display>(
+    fn no_such_field_err(
         &self,
-        span: Span,
-        field: T,
-        expr_t: &ty::TyS<'_>,
+        field: Ident,
+        expr_t: &'tcx ty::TyS<'tcx>,
     ) -> DiagnosticBuilder<'_> {
-        type_error_struct!(
+        let span = field.span;
+        debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
+
+        let mut err = type_error_struct!(
             self.tcx().sess,
-            span,
+            field.span,
             expr_t,
             E0609,
             "no field `{}` on type `{}`",
             field,
             expr_t
-        )
+        );
+
+        // try to add a suggestion in case the field is a nested field of a field of the Adt
+        if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
+            for candidate_field in fields.iter() {
+                if let Some(field_path) =
+                    self.check_for_nested_field(span, field, candidate_field, substs, vec![])
+                {
+                    let field_path_str = field_path
+                        .iter()
+                        .map(|id| id.name.to_ident_string())
+                        .collect::<Vec<String>>()
+                        .join(".");
+                    debug!("field_path_str: {:?}", field_path_str);
+
+                    err.span_suggestion_verbose(
+                        field.span.shrink_to_lo(),
+                        "one of the expressions' fields has a field of the same name",
+                        format!("{}.", field_path_str),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        err
+    }
+
+    fn get_field_candidates(
+        &self,
+        span: Span,
+        base_t: Ty<'tcx>,
+    ) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
+        debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
+
+        let mut autoderef = self.autoderef(span, base_t);
+        while let Some((base_t, _)) = autoderef.next() {
+            match base_t.kind() {
+                ty::Adt(base_def, substs) if !base_def.is_enum() => {
+                    let fields = &base_def.non_enum_variant().fields;
+                    // For compile-time reasons put a limit on number of fields we search
+                    if fields.len() > 100 {
+                        return None;
+                    }
+                    return Some((fields, substs));
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
+    /// This method is called after we have encountered a missing field error to recursively
+    /// search for the field
+    fn check_for_nested_field(
+        &self,
+        span: Span,
+        target_field: Ident,
+        candidate_field: &ty::FieldDef,
+        subst: SubstsRef<'tcx>,
+        mut field_path: Vec<Ident>,
+    ) -> Option<Vec<Ident>> {
+        debug!(
+            "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
+            span, candidate_field, field_path
+        );
+
+        if candidate_field.ident == target_field {
+            Some(field_path)
+        } else if field_path.len() > 3 {
+            // For compile-time reasons and to avoid infinite recursion we only check for fields
+            // up to a depth of three
+            None
+        } else {
+            // recursively search fields of `candidate_field` if it's a ty::Adt
+
+            field_path.push(candidate_field.ident.normalize_to_macros_2_0());
+            let field_ty = candidate_field.ty(self.tcx, subst);
+            if let Some((nested_fields, _)) = self.get_field_candidates(span, &field_ty) {
+                for field in nested_fields.iter() {
+                    let ident = field.ident.normalize_to_macros_2_0();
+                    if ident == target_field {
+                        return Some(field_path);
+                    } else {
+                        let field_path = field_path.clone();
+                        if let Some(path) = self.check_for_nested_field(
+                            span,
+                            target_field,
+                            field,
+                            subst,
+                            field_path,
+                        ) {
+                            return Some(path);
+                        }
+                    }
+                }
+            }
+            None
+        }
     }
 
     fn check_expr_index(
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 6b2cba62fa6..f039445bf77 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -184,10 +184,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let origin = if self.tcx.features().capture_disjoint_fields {
                     origin
                 } else {
-                    // FIXME(project-rfc-2229#26): Once rust-lang#80092 is merged, we should restrict the
-                    // precision of origin as well. Otherwise, this will cause issues when project-rfc-2229#26
-                    // is fixed as we might see Index projections in the origin, which we can't print because
-                    // we don't store enough information.
+                    // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
+                    //                             made, make sure we are selecting and restricting
+                    //                             the origin correctly.
                     (origin.0, Place { projections: vec![], ..origin.1 })
                 };
 
@@ -252,8 +251,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let capture = captured_place.info.capture_kind;
 
                 debug!(
-                    "place={:?} upvar_ty={:?} capture={:?}",
-                    captured_place.place, upvar_ty, capture
+                    "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
+                    captured_place.place, upvar_ty, capture, captured_place.mutability,
                 );
 
                 match capture {
@@ -419,19 +418,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 base => bug!("Expected upvar, found={:?}", base),
             };
 
-            // Arrays are captured in entirety, drop Index projections and projections
-            // after Index projections.
-            let first_index_projection =
-                place.projections.split(|proj| ProjectionKind::Index == proj.kind).next();
-            let place = Place {
-                base_ty: place.base_ty,
-                base: place.base,
-                projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()),
-            };
+            let place = restrict_capture_precision(place, capture_info.capture_kind);
 
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
-                    let min_cap_list = vec![ty::CapturedPlace { place, info: capture_info }];
+                    let mutability = self.determine_capture_mutability(&place);
+                    let min_cap_list =
+                        vec![ty::CapturedPlace { place, info: capture_info, mutability }];
                     root_var_min_capture_list.insert(var_hir_id, min_cap_list);
                     continue;
                 }
@@ -494,8 +487,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Only need to insert when we don't have an ancestor in the existing min capture list
             if !ancestor_found {
+                let mutability = self.determine_capture_mutability(&place);
                 let captured_place =
-                    ty::CapturedPlace { place: place.clone(), info: updated_capture_info };
+                    ty::CapturedPlace { place, info: updated_capture_info, mutability };
                 min_cap_list.push(captured_place);
             }
         }
@@ -615,6 +609,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
     }
+
+    /// A captured place is mutable if
+    /// 1. Projections don't include a Deref of an immut-borrow, **and**
+    /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
+    fn determine_capture_mutability(&self, place: &Place<'tcx>) -> hir::Mutability {
+        let var_hir_id = match place.base {
+            PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+            _ => unreachable!(),
+        };
+
+        let bm = *self
+            .typeck_results
+            .borrow()
+            .pat_binding_modes()
+            .get(var_hir_id)
+            .expect("missing binding mode");
+
+        let mut is_mutbl = match bm {
+            ty::BindByValue(mutability) => mutability,
+            ty::BindByReference(_) => hir::Mutability::Not,
+        };
+
+        for pointer_ty in place.deref_tys() {
+            match pointer_ty.kind() {
+                // We don't capture derefs of raw ptrs
+                ty::RawPtr(_) => unreachable!(),
+
+                // Derefencing a mut-ref allows us to mut the Place if we don't deref
+                // an immut-ref after on top of this.
+                ty::Ref(.., hir::Mutability::Mut) => is_mutbl = hir::Mutability::Mut,
+
+                // The place isn't mutable once we dereference a immutable reference.
+                ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not,
+
+                // Dereferencing a box doesn't change mutability
+                ty::Adt(def, ..) if def.is_box() => {}
+
+                unexpected_ty => bug!("deref of unexpected pointer type {:?}", unexpected_ty),
+            }
+        }
+
+        is_mutbl
+    }
 }
 
 struct InferBorrowKind<'a, 'tcx> {
@@ -960,6 +997,66 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     }
 }
 
+/// Truncate projections so that following rules are obeyed by the captured `place`:
+///
+/// - No Derefs in move closure, this will result in value behind a reference getting moved.
+/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
+///   them completely.
+/// - No Index projections are captured, since arrays are captured completely.
+fn restrict_capture_precision<'tcx>(
+    mut place: Place<'tcx>,
+    capture_kind: ty::UpvarCapture<'tcx>,
+) -> Place<'tcx> {
+    if place.projections.is_empty() {
+        // Nothing to do here
+        return place;
+    }
+
+    if place.base_ty.is_unsafe_ptr() {
+        place.projections.truncate(0);
+        return place;
+    }
+
+    let mut truncated_length = usize::MAX;
+    let mut first_deref_projection = usize::MAX;
+
+    for (i, proj) in place.projections.iter().enumerate() {
+        if proj.ty.is_unsafe_ptr() {
+            // Don't apply any projections on top of an unsafe ptr
+            truncated_length = truncated_length.min(i + 1);
+            break;
+        }
+        match proj.kind {
+            ProjectionKind::Index => {
+                // Arrays are completely captured, so we drop Index projections
+                truncated_length = truncated_length.min(i);
+                break;
+            }
+            ProjectionKind::Deref => {
+                // We only drop Derefs in case of move closures
+                // There might be an index projection or raw ptr ahead, so we don't stop here.
+                first_deref_projection = first_deref_projection.min(i);
+            }
+            ProjectionKind::Field(..) => {} // ignore
+            ProjectionKind::Subslice => {}  // We never capture this
+        }
+    }
+
+    let length = place
+        .projections
+        .len()
+        .min(truncated_length)
+        // In case of capture `ByValue` we want to not capture derefs
+        .min(match capture_kind {
+            ty::UpvarCapture::ByValue(..) => first_deref_projection,
+            ty::UpvarCapture::ByRef(..) => usize::MAX,
+        });
+
+    place.projections.truncate(length);
+
+    place
+}
+
 fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
     let variable_name = match place.base {
         PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 13f4d902d3b..785ce8d606b 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -89,7 +89,6 @@
 #![feature(coerce_unsized)]
 #![feature(const_btree_new)]
 #![feature(const_fn)]
-#![feature(const_in_array_repeat_expressions)]
 #![feature(cow_is_borrowed)]
 #![feature(const_cow_is_borrowed)]
 #![feature(dispatch_from_dyn)]
@@ -102,7 +101,6 @@
 #![feature(fn_traits)]
 #![feature(fundamental)]
 #![feature(inplace_iteration)]
-#![feature(int_bits_const)]
 #![feature(lang_items)]
 #![feature(layout_for_ptr)]
 #![feature(maybe_uninit_ref)]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 9b0b480a7e9..3218b3535c9 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -972,7 +972,7 @@ impl String {
         self.vec.try_reserve(additional)
     }
 
-    /// Tries to reserves the minimum capacity for exactly `additional` more elements to
+    /// Tries to reserve the minimum capacity for exactly `additional` more elements to
     /// be inserted in the given `String`. After calling `reserve_exact`,
     /// capacity will be greater than or equal to `self.len() + additional`.
     /// Does nothing if the capacity is already sufficient.
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 0b7eeab4e96..7b003546298 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -17,7 +17,6 @@
 #![feature(binary_heap_retain)]
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
-#![feature(int_bits_const)]
 #![feature(vecdeque_binary_search)]
 #![feature(slice_group_by)]
 
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 8fdd7c9e5d7..96affd17cc5 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -32,10 +32,9 @@ macro_rules! int_impl {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_bits_const)]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
         /// ```
-        #[unstable(feature = "int_bits_const", issue = "76904")]
+        #[stable(feature = "int_bits_const", since = "1.51.0")]
         pub const BITS: u32 = $BITS;
 
         /// Converts a string slice in a given base to an integer.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 9fccf3f72ce..aee424b9b13 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -32,10 +32,9 @@ macro_rules! uint_impl {
         /// # Examples
         ///
         /// ```
-        /// #![feature(int_bits_const)]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
         /// ```
-        #[unstable(feature = "int_bits_const", issue = "76904")]
+        #[stable(feature = "int_bits_const", since = "1.51.0")]
         pub const BITS: u32 = $BITS;
 
         /// Converts a string slice in a given base to an integer.
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index bc0e3e059c9..26dbcb8569b 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -70,7 +70,6 @@
 #![feature(partition_point)]
 #![feature(once_cell)]
 #![feature(unsafe_block_in_unsafe_fn)]
-#![feature(int_bits_const)]
 #![feature(nonzero_leading_trailing_zeros)]
 #![feature(const_option)]
 #![feature(integer_atomics)]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 9ce9c477ec0..99a0c67fc11 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -18,7 +18,6 @@
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
 )]
 #![feature(core_intrinsics)]
-#![feature(int_bits_const)]
 #![feature(lang_items)]
 #![feature(nll)]
 #![feature(panic_unwind)]
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 84449e48767..a8a4127d40a 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -1217,8 +1217,8 @@ impl Ipv6Addr {
 
     /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
     ///
-    /// A common mis-conception is to think that "unicast link-local addresses start with
-    /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses:
+    /// A common misconception is to think that "unicast link-local addresses start with
+    /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
     ///
     /// ```no_rust
     /// |   10     |
@@ -1228,9 +1228,9 @@ impl Ipv6Addr {
     /// +----------+-------------------------+----------------------------+
     /// ```
     ///
-    /// This method validates the format defined in the RFC and won't recognize the following
-    /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example.
-    /// If you need a less strict validation use [`Ipv6Addr::is_unicast_link_local()`] instead.
+    /// This method validates the format defined in the RFC and won't recognize addresses
+    /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
+    /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
     ///
     /// # Examples
     ///
@@ -1282,7 +1282,7 @@ impl Ipv6Addr {
     /// +----------+-------------------------+----------------------------+
     /// ```
     ///
-    /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be
+    /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
     /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
     /// If you need a strict validation fully compliant with the RFC, use
     /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
@@ -1362,7 +1362,7 @@ impl Ipv6Addr {
     }
 
     /// Returns [`true`] if this is an address reserved for documentation
-    /// (2001:db8::/32).
+    /// (`2001:db8::/32`).
     ///
     /// This property is defined in [IETF RFC 3849].
     ///
diff --git a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md
deleted file mode 100644
index 940916944bd..00000000000
--- a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# `const_in_array_repeat_expressions`
-
-The tracking issue for this feature is: [#49147]
-
-[#49147]: https://github.com/rust-lang/rust/issues/49147
-
-------------------------
-
-Relaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly
-speaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is
-`const` is itself also `const`.
diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.rs b/src/test/ui/array-slice-vec/repeat_empty_ok.rs
new file mode 100644
index 00000000000..25463ea5ee8
--- /dev/null
+++ b/src/test/ui/array-slice-vec/repeat_empty_ok.rs
@@ -0,0 +1,15 @@
+#![crate_type = "lib"]
+
+pub struct Header<'a> {
+    pub value: &'a [u8],
+}
+
+pub fn test() {
+    let headers = [Header{value: &[]}; 128];
+    //~^ ERROR the trait bound
+}
+
+pub fn test2() {
+    let headers = [Header{value: &[0]}; 128];
+    //~^ ERROR the trait bound
+}
diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
new file mode 100644
index 00000000000..85baa1268bf
--- /dev/null
+++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
+  --> $DIR/repeat_empty_ok.rs:8:19
+   |
+LL |     let headers = [Header{value: &[]}; 128];
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
+  --> $DIR/repeat_empty_ok.rs:13:19
+   |
+LL |     let headers = [Header{value: &[0]}; 128];
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.rs b/src/test/ui/closures/2229_closure_analysis/by_value.rs
new file mode 100644
index 00000000000..1007fb582e5
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/by_value.rs
@@ -0,0 +1,41 @@
+// Test that we handle derferences properly when only some of the captures are being moved with
+// `capture_disjoint_fields` enabled.
+
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug, Default)]
+struct SomeLargeType;
+struct MuchLargerType([SomeLargeType; 32]);
+
+// Ensure that we don't capture any derefs when moving captures into the closures,
+// i.e. only data from the enclosing stack is moved.
+fn big_box() {
+    let s = MuchLargerType(Default::default());
+    let b = Box::new(s);
+    let t = (b, 10);
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        let p = t.0.0;
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+        //~| NOTE: Min Capture t[(0, 0)] -> ByValue
+        println!("{} {:?}", t.1, p);
+        //~^ NOTE: Capturing t[(1, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture t[(1, 0)] -> ImmBorrow
+    };
+
+    c();
+}
+
+fn main() {
+    big_box();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/by_value.stderr b/src/test/ui/closures/2229_closure_analysis/by_value.stderr
new file mode 100644
index 00000000000..fe04dbef6d8
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/by_value.stderr
@@ -0,0 +1,67 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/by_value.rs:22:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/by_value.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/by_value.rs:25:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let p = t.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+  --> $DIR/by_value.rs:28:17
+   |
+LL |         let p = t.0.0;
+   |                 ^^^^^
+note: Capturing t[(1, 0)] -> ImmBorrow
+  --> $DIR/by_value.rs:31:29
+   |
+LL |         println!("{} {:?}", t.1, p);
+   |                             ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/by_value.rs:25:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let p = t.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[(0, 0)] -> ByValue
+  --> $DIR/by_value.rs:28:17
+   |
+LL |         let p = t.0.0;
+   |                 ^^^^^
+note: Min Capture t[(1, 0)] -> ImmBorrow
+  --> $DIR/by_value.rs:31:29
+   |
+LL |         println!("{} {:?}", t.1, p);
+   |                             ^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs
new file mode 100644
index 00000000000..1ea38e260b6
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs
@@ -0,0 +1,20 @@
+// Test that if we deref an immutable borrow to access a Place,
+// then we can't mutate the final place.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+fn main() {
+    let mut x = (format!(""), format!("X2"));
+    let mut y = (&x, "Y");
+    let z = (&mut y, "Z");
+
+    // `x.0` is mutable but we access `x` via `z.0.0`, which is an immutable reference and
+    // therefore can't be mutated.
+    let mut c = || {
+    //~^ ERROR: cannot borrow `z.0.0.0` as mutable, as it is behind a `&` reference
+        z.0.0.0 = format!("X1");
+    };
+
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
new file mode 100644
index 00000000000..861bc44b78d
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
@@ -0,0 +1,21 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/cant-mutate-imm-borrow.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0596]: cannot borrow `z.0.0.0` as mutable, as it is behind a `&` reference
+  --> $DIR/cant-mutate-imm-borrow.rs:14:17
+   |
+LL |     let mut c = || {
+   |                 ^^ cannot borrow as mutable
+LL |
+LL |         z.0.0.0 = format!("X1");
+   |         - mutable borrow occurs due to use of `z.0.0.0` in closure
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
new file mode 100644
index 00000000000..997ecc7dddd
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
@@ -0,0 +1,35 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+// Ensure that diagnostics for mutability error (because the root variable
+// isn't mutable) work with `capture_disjoint_fields` enabled.
+
+fn mut_error_struct() {
+    let x = (10, 10);
+    let y = (x, 10);
+    let z = (y, 10);
+
+    let mut c = || {
+        z.0.0.0 = 20;
+        //~^ ERROR: cannot assign to `z`, as it is not declared as mutable
+    };
+
+    c();
+}
+
+fn mut_error_box() {
+    let x = (10, 10);
+    let bx = Box::new(x);
+
+    let mut c = || {
+        bx.0 = 20;
+        //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable
+    };
+
+    c();
+}
+
+fn main() {
+    mut_error_struct();
+    mut_error_box();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
new file mode 100644
index 00000000000..5e15635ac6e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
@@ -0,0 +1,30 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/cant-mutate-imm.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0594]: cannot assign to `z`, as it is not declared as mutable
+  --> $DIR/cant-mutate-imm.rs:13:9
+   |
+LL |     let z = (y, 10);
+   |         - help: consider changing this to be mutable: `mut z`
+...
+LL |         z.0.0.0 = 20;
+   |         ^^^^^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `bx`, as it is not declared as mutable
+  --> $DIR/cant-mutate-imm.rs:25:9
+   |
+LL |     let bx = Box::new(x);
+   |         -- help: consider changing this to be mutable: `mut bx`
+...
+LL |         bx.0 = 20;
+   |         ^^^^^^^^^ cannot assign
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs
new file mode 100644
index 00000000000..676fde558df
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs
@@ -0,0 +1,38 @@
+// Test that we can't mutate a place if we need to deref an imm-borrow
+// to reach it.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+fn imm_mut_ref() {
+    let mut x = String::new();
+    let y = String::new();
+    let mref_x = &mut x;
+    let ref_mref_x = &mref_x;
+
+    let c = || {
+    //~^ ERROR: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
+        **ref_mref_x = y;
+    };
+
+    c();
+}
+
+fn mut_imm_ref() {
+    let x = String::new();
+    let y = String::new();
+    let mut ref_x = &x;
+    let mref_ref_x = &mut ref_x;
+
+    let c = || {
+    //~^ ERROR: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
+        **mref_ref_x = y;
+    };
+
+    c();
+}
+
+fn main() {
+    imm_mut_ref();
+    mut_imm_ref();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
new file mode 100644
index 00000000000..8cb2ed2235d
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
@@ -0,0 +1,33 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mut_ref.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0596]: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
+  --> $DIR/mut_ref.rs:13:13
+   |
+LL |     let ref_mref_x = &mref_x;
+   |                      ------- help: consider changing this to be a mutable reference: `&mut mref_x`
+LL | 
+LL |     let c = || {
+   |             ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+LL |
+LL |         **ref_mref_x = y;
+   |           ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure
+
+error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
+  --> $DIR/mut_ref.rs:27:13
+   |
+LL |     let c = || {
+   |             ^^ cannot borrow as mutable
+LL |
+LL |         **mref_ref_x = y;
+   |           ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/move_closure.rs
new file mode 100644
index 00000000000..8bdc999ca3c
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/move_closure.rs
@@ -0,0 +1,72 @@
+// Test that move closures drop derefs with `capture_disjoint_fields` enabled.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+// Test we truncate derefs properly
+fn simple_ref() {
+    let mut s = 10;
+    let ref_s = &mut s;
+
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        *ref_s += 10;
+        //~^ NOTE: Capturing ref_s[Deref] -> ByValue
+        //~| NOTE: Min Capture ref_s[] -> ByValue
+    };
+    c();
+}
+
+// Test we truncate derefs properly
+fn struct_contains_ref_to_another_struct() {
+    struct S(String);
+    struct T<'a>(&'a mut S);
+
+    let mut s = S("s".into());
+    let t = T(&mut s);
+
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        t.0.0 = "new s".into();
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+        //~| NOTE: Min Capture t[(0, 0)] -> ByValue
+    };
+
+    c();
+}
+
+// Test that we don't reduce precision when there is nothing deref.
+fn no_ref() {
+    struct S(String);
+    struct T(S);
+
+    let t = T(S("s".into()));
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    move || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        t.0.0 = "new S".into();
+        //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
+        //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
+    };
+    c();
+}
+
+fn main() {
+    simple_ref();
+    struct_contains_ref_to_another_struct();
+    no_ref();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr
new file mode 100644
index 00000000000..a745f14598e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr
@@ -0,0 +1,147 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:14:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:35:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/move_closure.rs:55:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/move_closure.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:17:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         *ref_s += 10;
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing ref_s[Deref] -> ByValue
+  --> $DIR/move_closure.rs:20:9
+   |
+LL |         *ref_s += 10;
+   |         ^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:17:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         *ref_s += 10;
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture ref_s[] -> ByValue
+  --> $DIR/move_closure.rs:20:9
+   |
+LL |         *ref_s += 10;
+   |         ^^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:38:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         t.0.0 = "new s".into();
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:41:9
+   |
+LL |         t.0.0 = "new s".into();
+   |         ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:38:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         t.0.0 = "new s".into();
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:41:9
+   |
+LL |         t.0.0 = "new s".into();
+   |         ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/move_closure.rs:58:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         t.0.0 = "new S".into();
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:61:9
+   |
+LL |         t.0.0 = "new S".into();
+   |         ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/move_closure.rs:58:5
+   |
+LL | /     move || {
+LL | |
+LL | |
+LL | |         t.0.0 = "new S".into();
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[(0, 0),(0, 0)] -> ByValue
+  --> $DIR/move_closure.rs:61:9
+   |
+LL |         t.0.0 = "new S".into();
+   |         ^^^^^
+
+error: aborting due to 9 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs
new file mode 100644
index 00000000000..9a93e6cf1e1
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+// Test that ByValue captures compile sucessefully especially when the captures are
+// derefenced within the closure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug, Default)]
+struct SomeLargeType;
+struct MuchLargerType([SomeLargeType; 32]);
+
+fn big_box() {
+    let s = MuchLargerType(Default::default());
+    let b = Box::new(s);
+    let t = (b, 10);
+
+    let c = || {
+        let p = t.0.0;
+        println!("{} {:?}", t.1, p);
+    };
+
+    c();
+}
+
+fn main() {
+    big_box();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr
new file mode 100644
index 00000000000..98715c6b943
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/by_value.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs
new file mode 100644
index 00000000000..4007a5a48aa
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs
@@ -0,0 +1,64 @@
+// run-pass
+
+// Test that move closures compile properly with `capture_disjoint_fields` enabled.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+fn simple_ref() {
+    let mut s = 10;
+    let ref_s = &mut s;
+
+    let mut c = move || {
+        *ref_s += 10;
+    };
+    c();
+}
+
+fn struct_contains_ref_to_another_struct() {
+    struct S(String);
+    struct T<'a>(&'a mut S);
+
+    let mut s = S("s".into());
+    let t = T(&mut s);
+
+    let mut c = move || {
+        t.0.0 = "new s".into();
+    };
+
+    c();
+}
+
+#[derive(Debug)]
+struct S(String);
+
+#[derive(Debug)]
+struct T(S);
+
+fn no_ref() {
+    let mut t = T(S("s".into()));
+    let mut c = move || {
+        t.0.0 = "new S".into();
+    };
+    c();
+}
+
+fn no_ref_nested() {
+    let mut t = T(S("s".into()));
+    let c = || {
+        println!("{:?}", t.0);
+        let mut c = move || {
+            t.0.0 = "new S".into();
+            println!("{:?}", t.0.0);
+        };
+        c();
+    };
+    c();
+}
+
+fn main() {
+    simple_ref();
+    struct_contains_ref_to_another_struct();
+    no_ref();
+    no_ref_nested();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr
new file mode 100644
index 00000000000..c1d8ba575d6
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/move_closure.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs
new file mode 100644
index 00000000000..315622443c3
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs
@@ -0,0 +1,56 @@
+// run-pass
+
+// Test that we can mutate a place through a mut-borrow
+// that is captured by the closure
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+// Check that we can mutate when one deref is required
+fn mut_ref_1() {
+    let mut x = String::new();
+    let rx = &mut x;
+
+    let mut c = || {
+        *rx = String::new();
+    };
+
+    c();
+}
+
+// Similar example as mut_ref_1, we don't deref the imm-borrow here,
+// and so we are allowed to mutate.
+fn mut_ref_2() {
+    let x = String::new();
+    let y = String::new();
+    let mut ref_x = &x;
+    let m_ref_x = &mut ref_x;
+
+    let mut c = || {
+        *m_ref_x = &y;
+    };
+
+    c();
+}
+
+// Check that we can mutate when multiple derefs of mut-borrows are required to reach
+// the target place.
+// It works because all derefs are mutable, if either of them was an immutable
+// borrow, then we would not be able to deref.
+fn mut_mut_ref() {
+    let mut x = String::new();
+    let mut mref_x = &mut x;
+    let m_mref_x = &mut mref_x;
+
+    let mut c = || {
+        **m_mref_x = String::new();
+    };
+
+    c();
+}
+
+fn main() {
+    mut_ref_1();
+    mut_ref_2();
+    mut_mut_ref();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr
new file mode 100644
index 00000000000..4b37a0b405f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mut_ref.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs
new file mode 100644
index 00000000000..2dba923647a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs
@@ -0,0 +1,45 @@
+// run-pass
+
+// Test that we can mutate a place through a mut-borrow
+// that is captured by the closure
+
+// More specifically we test that the if the mutable reference isn't root variable of a capture
+// but rather accessed while acessing the precise capture.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+fn mut_tuple() {
+    let mut t = (10, 10);
+
+    let t1 = (&mut t, 10);
+
+    let mut c = || {
+        // Mutable because (*t.0) is mutable
+        t1.0.0 += 10;
+    };
+
+    c();
+}
+
+fn mut_tuple_nested() {
+    let mut t = (10, 10);
+
+    let t1 = (&mut t, 10);
+
+    let mut c = || {
+        let mut c = || {
+            // Mutable because (*t.0) is mutable
+            t1.0.0 += 10;
+        };
+
+        c();
+    };
+
+    c();
+}
+
+fn main() {
+    mut_tuple();
+    mut_tuple_nested();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr
new file mode 100644
index 00000000000..418ab29098b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mut_ref_struct_mem.rs:9:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs
new file mode 100644
index 00000000000..f6e9862b26c
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs
@@ -0,0 +1,47 @@
+// run-pass
+
+// Test that we can use raw ptrs when using `capture_disjoint_fields`.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct S {
+    s: String,
+    t: String,
+}
+
+struct T(*const S);
+
+fn unsafe_imm() {
+    let s = "".into();
+    let t = "".into();
+    let my_speed: Box<S> = Box::new(S { s, t });
+
+    let p : *const S = Box::into_raw(my_speed);
+    let t = T(p);
+
+    let c = || unsafe {
+        println!("{:?}", (*t.0).s);
+    };
+
+    c();
+}
+
+fn unsafe_mut() {
+    let s = "".into();
+    let t = "".into();
+    let mut my_speed: Box<S> = Box::new(S { s, t });
+    let p : *mut S = &mut *my_speed;
+
+    let c = || {
+        let x = unsafe { &mut (*p).s };
+        *x = "s".into();
+    };
+    c();
+}
+
+fn main() {
+    unsafe_mut();
+    unsafe_imm();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr
new file mode 100644
index 00000000000..c64c8b72e81
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsafe_ptr.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs
new file mode 100644
index 00000000000..79d3ecc2d2b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.rs
@@ -0,0 +1,63 @@
+// Test that we restrict precision of a capture when we access a raw ptr,
+// i.e. the capture doesn't deref the raw ptr.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct S {
+    s: String,
+    t: String,
+}
+
+struct T(*const S);
+
+fn unsafe_imm() {
+    let s = "".into();
+    let t = "".into();
+    let my_speed: Box<S> = Box::new(S { s, t });
+
+    let p : *const S = Box::into_raw(my_speed);
+    let t = T(p);
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+     || unsafe {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        println!("{:?}", (*t.0).s);
+        //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture t[(0, 0)] -> ImmBorrow
+    };
+
+    c();
+}
+
+fn unsafe_mut() {
+    let s = "".into();
+    let t = "".into();
+    let mut my_speed: Box<S> = Box::new(S { s, t });
+    let p : *mut S = &mut *my_speed;
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let x = unsafe { &mut (*p).s };
+        //~^ NOTE: Capturing p[Deref,(0, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture p[] -> ImmBorrow
+        *x = "s".into();
+    };
+    c();
+}
+
+fn main() {
+    unsafe_mut();
+    unsafe_imm();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr
new file mode 100644
index 00000000000..4508b2426e8
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/unsafe_ptr.stderr
@@ -0,0 +1,102 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/unsafe_ptr.rs:26:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/unsafe_ptr.rs:46:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/unsafe_ptr.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/unsafe_ptr.rs:29:6
+   |
+LL | /      || unsafe {
+LL | |
+LL | |
+LL | |         println!("{:?}", (*t.0).s);
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/unsafe_ptr.rs:32:26
+   |
+LL |         println!("{:?}", (*t.0).s);
+   |                          ^^^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/unsafe_ptr.rs:29:6
+   |
+LL | /      || unsafe {
+LL | |
+LL | |
+LL | |         println!("{:?}", (*t.0).s);
+LL | |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[(0, 0)] -> ImmBorrow
+  --> $DIR/unsafe_ptr.rs:32:26
+   |
+LL |         println!("{:?}", (*t.0).s);
+   |                          ^^^^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/unsafe_ptr.rs:49:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = unsafe { &mut (*p).s };
+...  |
+LL | |         *x = "s".into();
+LL | |     };
+   | |_____^
+   |
+note: Capturing p[Deref,(0, 0)] -> ImmBorrow
+  --> $DIR/unsafe_ptr.rs:52:31
+   |
+LL |         let x = unsafe { &mut (*p).s };
+   |                               ^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/unsafe_ptr.rs:49:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = unsafe { &mut (*p).s };
+...  |
+LL | |         *x = "s".into();
+LL | |     };
+   | |_____^
+   |
+note: Min Capture p[] -> ImmBorrow
+  --> $DIR/unsafe_ptr.rs:52:31
+   |
+LL |         let x = unsafe { &mut (*p).s };
+   |                               ^^^^^^
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/issue-71202.rs b/src/test/ui/const-generics/issue-71202.rs
new file mode 100644
index 00000000000..78dee1717f1
--- /dev/null
+++ b/src/test/ui/const-generics/issue-71202.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features, const_evaluatable_unchecked)]
+
+use std::marker::PhantomData;
+
+struct DataHolder<T> {
+    item: T,
+}
+
+impl<T: Copy> DataHolder<T> {
+    const ITEM_IS_COPY: [(); 1 - {
+        trait NotCopy {
+            const VALUE: bool = false;
+        }
+
+        impl<__Type: ?Sized> NotCopy for __Type {}
+
+        struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
+
+        impl<__Type> IsCopy<__Type>
+        where
+            __Type: Sized + Copy,
+        {
+            const VALUE: bool = true;
+        }
+
+        <IsCopy<T>>::VALUE
+    } as usize] = [];
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs b/src/test/ui/consts/const-blocks/const-repeat.rs
index 65d02317d34..65d02317d34 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs
+++ b/src/test/ui/consts/const-blocks/const-repeat.rs
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-const.rs
index da1bae1be8d..7936af75d84 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-const.rs
+++ b/src/test/ui/consts/const-blocks/fn-call-in-const.rs
@@ -1,7 +1,7 @@
 // run-pass
 
-#![allow(unused)]
-#![feature(const_in_array_repeat_expressions)]
+#![feature(inline_const)]
+#![allow(unused, incomplete_features)]
 
 // Some type that is not copyable.
 struct Bar;
@@ -18,6 +18,6 @@ const _: [u32; 2] = [type_copy(); 2];
 
 // This is allowed because all promotion contexts use the explicit rules for promotability when
 // inside an explicit const context.
-const _: [Option<Bar>; 2] = [type_no_copy(); 2];
+const _: [Option<Bar>; 2] = [const { type_no_copy() }; 2];
 
 fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
index d40facf232a..19217843759 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs
+++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
@@ -1,5 +1,3 @@
-#![feature(const_in_array_repeat_expressions)]
-
 // Some type that is not copyable.
 struct Bar;
 
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
index 48092432bb1..b75452cd217 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr
+++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/fn-call-in-non-const.rs:16:31
+  --> $DIR/fn-call-in-non-const.rs:14:31
    |
 LL |     let _: [Option<Bar>; 2] = [no_copy(); 2];
    |                               ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs b/src/test/ui/consts/const-blocks/migrate-fail.rs
index d04b0b7e168..bb12139a7ba 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs
+++ b/src/test/ui/consts/const-blocks/migrate-fail.rs
@@ -1,6 +1,5 @@
 // ignore-compare-mode-nll
 // compile-flags: -Z borrowck=migrate
-#![feature(const_in_array_repeat_expressions)]
 #![allow(warnings)]
 
 // Some type that is not copyable.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr
index 476d48fd496..0fdbbc36288 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr
+++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:14:37
+  --> $DIR/migrate-fail.rs:13:37
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
@@ -9,7 +9,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: the `Copy` trait is required because the repeated element will be copied
 
 error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:20:37
+  --> $DIR/migrate-fail.rs:19:37
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs b/src/test/ui/consts/const-blocks/migrate-pass.rs
index bfa8ebcfdd3..3195717fa38 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs
+++ b/src/test/ui/consts/const-blocks/migrate-pass.rs
@@ -1,7 +1,6 @@
 // check-pass
 // compile-flags: -Z borrowck=migrate
 // ignore-compare-mode-nll
-#![feature(const_in_array_repeat_expressions)]
 #![allow(warnings)]
 
 // Some type that is not copyable.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs b/src/test/ui/consts/const-blocks/nll-fail.rs
index 2d5c59d112e..871387c1fd0 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs
+++ b/src/test/ui/consts/const-blocks/nll-fail.rs
@@ -1,5 +1,4 @@
 // ignore-compare-mode-nll
-#![feature(const_in_array_repeat_expressions, nll)]
 #![allow(warnings)]
 
 // Some type that is not copyable.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr
index 3aa69996ff7..81220856359 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr
+++ b/src/test/ui/consts/const-blocks/nll-fail.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:13:37
+  --> $DIR/nll-fail.rs:12:37
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
@@ -9,7 +9,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: the `Copy` trait is required because the repeated element will be copied
 
 error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:19:37
+  --> $DIR/nll-fail.rs:18:37
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs b/src/test/ui/consts/const-blocks/nll-pass.rs
index a304f877ab7..d8defa19483 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs
+++ b/src/test/ui/consts/const-blocks/nll-pass.rs
@@ -1,7 +1,6 @@
 // check-pass
 // ignore-compare-mode-nll
 #![allow(warnings)]
-#![feature(const_in_array_repeat_expressions, nll)]
 
 // Some type that is not copyable.
 struct Bar;
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs b/src/test/ui/consts/const-blocks/run-pass.rs
index 27bf5dabf56..e11f69babf7 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs
+++ b/src/test/ui/consts/const-blocks/run-pass.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(const_in_array_repeat_expressions)]
 
 #[derive(Debug, Eq, PartialEq)]
 struct Bar;
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs b/src/test/ui/consts/const-blocks/trait-error.rs
index f8df7aafa60..5a614cbdd15 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs
+++ b/src/test/ui/consts/const-blocks/trait-error.rs
@@ -1,5 +1,3 @@
-#![feature(const_in_array_repeat_expressions)]
-
 #[derive(Copy, Clone)]
 struct Foo<T>(T);
 
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr
index 26de67e50fa..26e2848e7f7 100644
--- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr
+++ b/src/test/ui/consts/const-blocks/trait-error.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Foo<String>: Copy` is not satisfied
-  --> $DIR/trait-error.rs:7:5
+  --> $DIR/trait-error.rs:5:5
    |
 LL |     [Foo(String::new()); 4];
    |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo<String>`
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
deleted file mode 100644
index 5ed302bbff3..00000000000
--- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![allow(warnings)]
-
-struct Bar;
-
-// This function would compile with the feature gate, and tests that it is suggested.
-fn foo() {
-    let arr: [Option<String>; 2] = [None::<String>; 2];
-    //~^ ERROR the trait bound `Option<String>: Copy` is not satisfied [E0277]
-}
-
-// This function would not compile with the feature gate, and tests that it is not suggested.
-fn bar() {
-    let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
-    //~^ ERROR the trait bound `Option<String>: Copy` is not satisfied [E0277]
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
deleted file mode 100644
index ca1706169af..00000000000
--- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: the trait bound `Option<String>: Copy` is not satisfied
-  --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36
-   |
-LL |     let arr: [Option<String>; 2] = [None::<String>; 2];
-   |                                    ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<String>`
-   |
-   = help: the following implementations were found:
-             <Option<T> as Copy>
-   = note: the `Copy` trait is required because the repeated element will be copied
-   = note: this array initializer can be evaluated at compile-time, see issue #49147 <https://github.com/rust-lang/rust/issues/49147> for more information
-   = help: add `#![feature(const_in_array_repeat_expressions)]` to the crate attributes to enable
-
-error[E0277]: the trait bound `Option<String>: Copy` is not satisfied
-  --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:13:36
-   |
-LL |     let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<String>`
-   |
-   = help: the following implementations were found:
-             <Option<T> as Copy>
-   = note: the `Copy` trait is required because the repeated element will be copied
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs
new file mode 100644
index 00000000000..98b408daa02
--- /dev/null
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs
@@ -0,0 +1,43 @@
+// In rustc_typeck::check::expr::no_such_field_err we recursively
+// look in subfields for the field. This recursive search is limited
+// in depth for compile-time reasons and to avoid infinite recursion
+// in case of cycles. This file tests that the limit in the recursion
+// depth is enforced.
+
+struct Foo {
+    first: Bar,
+    second: u32,
+    third: u32,
+}
+
+struct Bar {
+    bar: C,
+}
+
+struct C {
+    c: D,
+}
+
+struct D {
+    test: E,
+}
+
+struct E {
+    e: F,
+}
+
+struct F {
+    f: u32,
+}
+
+fn main() {
+    let f = F { f: 6 };
+    let e = E { e: f };
+    let d = D { test: e };
+    let c = C { c: d };
+    let bar = Bar { bar: c };
+    let fooer = Foo { first: bar, second: 4, third: 5 };
+
+    let test = fooer.f;
+    //~^ ERROR no field
+}
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr
new file mode 100644
index 00000000000..b294f4da7db
--- /dev/null
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr
@@ -0,0 +1,11 @@
+error[E0609]: no field `f` on type `Foo`
+  --> $DIR/non-existent-field-present-in-subfield-recursion-limit.rs:41:22
+   |
+LL |     let test = fooer.f;
+   |                      ^ unknown field
+   |
+   = note: available fields are: `first`, `second`, `third`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed b/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed
new file mode 100644
index 00000000000..167548a89de
--- /dev/null
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+
+struct Foo {
+    first: Bar,
+    _second: u32,
+    _third: u32,
+}
+
+struct Bar {
+    bar: C,
+}
+
+struct C {
+    c: D,
+}
+
+struct D {
+    test: E,
+}
+
+struct E {
+    _e: F,
+}
+
+struct F {
+    _f: u32,
+}
+
+fn main() {
+    let f = F { _f: 6 };
+    let e = E { _e: f };
+    let d = D { test: e };
+    let c = C { c: d };
+    let bar = Bar { bar: c };
+    let fooer = Foo { first: bar, _second: 4, _third: 5 };
+
+    let _test = &fooer.first.bar.c;
+    //~^ ERROR no field
+
+    let _test2 = fooer.first.bar.c.test;
+    //~^ ERROR no field
+}
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs b/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs
new file mode 100644
index 00000000000..81cc1af4dff
--- /dev/null
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+
+struct Foo {
+    first: Bar,
+    _second: u32,
+    _third: u32,
+}
+
+struct Bar {
+    bar: C,
+}
+
+struct C {
+    c: D,
+}
+
+struct D {
+    test: E,
+}
+
+struct E {
+    _e: F,
+}
+
+struct F {
+    _f: u32,
+}
+
+fn main() {
+    let f = F { _f: 6 };
+    let e = E { _e: f };
+    let d = D { test: e };
+    let c = C { c: d };
+    let bar = Bar { bar: c };
+    let fooer = Foo { first: bar, _second: 4, _third: 5 };
+
+    let _test = &fooer.c;
+    //~^ ERROR no field
+
+    let _test2 = fooer.test;
+    //~^ ERROR no field
+}
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr b/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr
new file mode 100644
index 00000000000..ddb7476ec6e
--- /dev/null
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield.stderr
@@ -0,0 +1,27 @@
+error[E0609]: no field `c` on type `Foo`
+  --> $DIR/non-existent-field-present-in-subfield.rs:37:24
+   |
+LL |     let _test = &fooer.c;
+   |                        ^ unknown field
+   |
+   = note: available fields are: `first`, `_second`, `_third`
+help: one of the expressions' fields has a field of the same name
+   |
+LL |     let _test = &fooer.first.bar.c;
+   |                        ^^^^^^^^^^
+
+error[E0609]: no field `test` on type `Foo`
+  --> $DIR/non-existent-field-present-in-subfield.rs:40:24
+   |
+LL |     let _test2 = fooer.test;
+   |                        ^^^^ unknown field
+   |
+   = note: available fields are: `first`, `_second`, `_third`
+help: one of the expressions' fields has a field of the same name
+   |
+LL |     let _test2 = fooer.first.bar.c.test;
+   |                        ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/unused/unused-closure.rs b/src/test/ui/unused/unused-closure.rs
index 5100636842b..c96c907318c 100644
--- a/src/test/ui/unused/unused-closure.rs
+++ b/src/test/ui/unused/unused-closure.rs
@@ -2,7 +2,6 @@
 // edition:2018
 
 #![feature(async_closure)]
-#![feature(const_in_array_repeat_expressions)]
 #![feature(generators)]
 #![deny(unused_must_use)]
 
@@ -18,10 +17,6 @@ fn unused() {
 
     [Box::new([|| {}; 10]); 1]; //~ ERROR unused array of boxed arrays of closures that must be used
 
-    [|| { //~ ERROR unused array of generators that must be used
-        yield 42u32;
-    }; 42];
-
     vec![|| "a"].pop().unwrap(); //~ ERROR unused closure that must be used
 
     let b = false;
diff --git a/src/test/ui/unused/unused-closure.stderr b/src/test/ui/unused/unused-closure.stderr
index f8b4cbb02c4..265d3e8e075 100644
--- a/src/test/ui/unused/unused-closure.stderr
+++ b/src/test/ui/unused/unused-closure.stderr
@@ -1,5 +1,5 @@
 error: unused closure that must be used
-  --> $DIR/unused-closure.rs:10:5
+  --> $DIR/unused-closure.rs:9:5
    |
 LL | /     || {
 LL | |         println!("Hello!");
@@ -7,14 +7,14 @@ LL | |     };
    | |______^
    |
 note: the lint level is defined here
-  --> $DIR/unused-closure.rs:7:9
+  --> $DIR/unused-closure.rs:6:9
    |
 LL | #![deny(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
    = note: closures are lazy and do nothing unless called
 
 error: unused implementer of `Future` that must be used
-  --> $DIR/unused-closure.rs:14:5
+  --> $DIR/unused-closure.rs:13:5
    |
 LL |     async {};
    |     ^^^^^^^^^
@@ -22,7 +22,7 @@ LL |     async {};
    = note: futures do nothing unless you `.await` or poll them
 
 error: unused closure that must be used
-  --> $DIR/unused-closure.rs:15:5
+  --> $DIR/unused-closure.rs:14:5
    |
 LL |     || async {};
    |     ^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL |     || async {};
    = note: closures are lazy and do nothing unless called
 
 error: unused closure that must be used
-  --> $DIR/unused-closure.rs:16:5
+  --> $DIR/unused-closure.rs:15:5
    |
 LL |     async || {};
    |     ^^^^^^^^^^^^
@@ -38,25 +38,15 @@ LL |     async || {};
    = note: closures are lazy and do nothing unless called
 
 error: unused array of boxed arrays of closures that must be used
-  --> $DIR/unused-closure.rs:19:5
+  --> $DIR/unused-closure.rs:18:5
    |
 LL |     [Box::new([|| {}; 10]); 1];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
-error: unused array of generators that must be used
-  --> $DIR/unused-closure.rs:21:5
-   |
-LL | /     [|| {
-LL | |         yield 42u32;
-LL | |     }; 42];
-   | |___________^
-   |
-   = note: generators are lazy and do nothing unless resumed
-
 error: unused closure that must be used
-  --> $DIR/unused-closure.rs:25:5
+  --> $DIR/unused-closure.rs:20:5
    |
 LL |     vec![|| "a"].pop().unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,12 +54,12 @@ LL |     vec![|| "a"].pop().unwrap();
    = note: closures are lazy and do nothing unless called
 
 error: unused closure that must be used
-  --> $DIR/unused-closure.rs:28:9
+  --> $DIR/unused-closure.rs:23:9
    |
 LL |         || true;
    |         ^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
 
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors