From 5f74ef4fb1d86d80a3052e772010e613353dbfa7 Mon Sep 17 00:00:00 2001
From: Caio <c410.f3r@gmail.com>
Date: Tue, 18 Jan 2022 19:38:17 -0300
Subject: [PATCH] Formally implement let chains

---
 compiler/rustc_ast_lowering/src/expr.rs       |  18 +-
 compiler/rustc_ast_passes/src/feature_gate.rs |   6 +-
 compiler/rustc_feature/src/active.rs          |   2 +-
 compiler/rustc_middle/src/thir.rs             |   2 +-
 .../rustc_mir_build/src/build/expr/into.rs    |  16 +-
 .../rustc_mir_build/src/build/matches/mod.rs  |  19 ++
 compiler/rustc_mir_build/src/build/scope.rs   |   2 +-
 compiler/rustc_mir_build/src/thir/cx/expr.rs  |   1 -
 .../src/thir/pattern/check_match.rs           |  43 +++-
 src/test/ui/expr/if/attrs/let-chains-attr.rs  |   2 +-
 .../ui/expr/if/attrs/let-chains-attr.stderr   |  11 -
 src/test/ui/mir/mir_let_chains_drop_order.rs  |  93 ++++++++
 src/test/ui/pattern/issue-82290.rs            |   9 -
 src/test/ui/pattern/issue-82290.stderr        |  21 --
 .../ui/rfc-2294-if-let-guard/feature-gate.rs  |  32 +--
 .../rfc-2294-if-let-guard/feature-gate.stderr |  48 ++--
 .../ast-lowering-does-not-wrap-let-chains.rs  |  15 ++
 .../ast-pretty-check.rs                       |   2 +-
 .../ast-pretty-check.stdout                   |   2 +-
 .../chains-without-let.rs                     |  20 ++
 .../chains-without-let.stderr                 |  21 ++
 .../disallowed-positions.rs                   |   1 -
 .../disallowed-positions.stderr               | 221 +++++++++---------
 .../ui/rfc-2497-if-let-chains/feature-gate.rs |  64 ++---
 .../feature-gate.stderr                       |  96 +++-----
 .../irrefutable-lets.rs                       |  27 +++
 .../ui/rfc-2497-if-let-chains/issue-88498.rs  |  16 ++
 .../ui/rfc-2497-if-let-chains/issue-90722.rs  |  11 +
 .../ui/rfc-2497-if-let-chains/issue-92145.rs  |  11 +
 .../no-double-assigments.rs                   |   9 +
 .../then-else-blocks.rs                       |  35 +++
 31 files changed, 536 insertions(+), 340 deletions(-)
 delete mode 100644 src/test/ui/expr/if/attrs/let-chains-attr.stderr
 create mode 100644 src/test/ui/mir/mir_let_chains_drop_order.rs
 delete mode 100644 src/test/ui/pattern/issue-82290.rs
 delete mode 100644 src/test/ui/pattern/issue-82290.stderr
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
 create mode 100644 src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs

diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 470e9114217c6..6c172d59f837b 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -392,14 +392,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
     // in a temporary block.
     fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
-        match cond.kind {
-            hir::ExprKind::Let(..) => cond,
-            _ => {
-                let span_block =
-                    self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
-                self.expr_drop_temps(span_block, cond, AttrVec::new())
+        fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
+            match expr.kind {
+                hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+                hir::ExprKind::Let(..) => true,
+                _ => false,
             }
         }
+        if has_let_expr(cond) {
+            cond
+        } else {
+            let reason = DesugaringKind::CondTemporary;
+            let span_block = self.mark_span_with_reason(reason, cond.span, None);
+            self.expr_drop_temps(span_block, cond, AttrVec::new())
+        }
     }
 
     // We desugar: `'label: while $cond $body` into:
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 89671788255a9..a6ecfa4520608 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -707,11 +707,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
         "`if let` guards are experimental",
         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
     );
-    gate_all!(
-        let_chains,
-        "`let` expressions in this position are experimental",
-        "you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`"
-    );
+    gate_all!(let_chains, "`let` expressions in this position are unstable");
     gate_all!(
         async_closure,
         "async closures are unstable",
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 47010ea3ab613..0b65a5ff3ecc3 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -415,7 +415,7 @@ declare_features! (
     // Allows setting the threshold for the `large_assignments` lint.
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allows `if/while p && let q = r && ...` chains.
-    (incomplete, let_chains, "1.37.0", Some(53667), None),
+    (active, let_chains, "1.37.0", Some(53667), None),
     /// Allows `let...else` statements.
     (active, let_else, "1.56.0", Some(87335), None),
     /// Allows `#[link(..., cfg(..))]`.
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index eef42666f2a07..11dc69ab71566 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -213,7 +213,7 @@ pub struct Expr<'tcx> {
 
 #[derive(Debug, HashStable)]
 pub enum ExprKind<'tcx> {
-    /// `Scope`s are used to explicitely mark destruction scopes,
+    /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
     Scope {
         region_scope: region::Scope,
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 43060ecfced12..da8fbdbf3bce4 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -90,17 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 };
 
                 let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(
-                    then_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-                this.cfg.terminate(
-                    else_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-
+                this.cfg.goto(then_blk, source_info, join_block);
+                this.cfg.goto(else_blk, source_info, join_block);
                 join_block.unit()
             }
             ExprKind::Let { expr, ref pat } => {
@@ -109,8 +100,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
                 });
 
-                let join_block = this.cfg.start_new_block();
-
                 this.cfg.push_assign_constant(
                     true_block,
                     source_info,
@@ -133,6 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
 
+                let join_block = this.cfg.start_new_block();
                 this.cfg.goto(true_block, source_info, join_block);
                 this.cfg.goto(false_block, source_info, join_block);
                 join_block.unit()
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index e3a05e01ea8f0..85950d8241940 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -47,6 +47,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let expr_span = expr.span;
 
         match expr.kind {
+            ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
+                let lhs_then_block = unpack!(this.then_else_break(
+                    block,
+                    &this.thir[lhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                let rhs_then_block = unpack!(this.then_else_break(
+                    lhs_then_block,
+                    &this.thir[rhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                rhs_then_block.unit()
+            }
             ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, this.source_info(expr_span));
                 this.in_scope(region_scope, lint_level, |this| {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index fc46c54c2fc35..84d6c1d2db87f 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -498,7 +498,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// if let Some(x) = a && let Some(y) = b && let Some(z) = c { ... }
     ///
-    /// there are three possible ways the condition can be false and we may have
+    /// There are three possible ways the condition can be false and we may have
     /// to drop `x`, `x` and `y`, or neither depending on which binding fails.
     /// To handle this correctly we use a `DropTree` in a similar way to a
     /// `loop` expression and 'break' out on all of the 'else' paths.
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 750677f161e44..a43388808cd5c 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -315,7 +315,6 @@ impl<'tcx> Cx<'tcx> {
                             lhs: self.mirror_expr(lhs),
                             rhs: self.mirror_expr(rhs),
                         },
-
                         _ => {
                             let op = bin_op(op.node);
                             ExprKind::Binary {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 868dd195f3a63..34204c3852ad0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -17,6 +17,7 @@ use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
 use rustc_session::Session;
+use rustc_span::source_map::Spanned;
 use rustc_span::{DesugaringKind, ExpnKind, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -445,6 +446,10 @@ fn check_let_reachability<'p, 'tcx>(
     pat: &'p DeconstructedPat<'p, 'tcx>,
     span: Span,
 ) {
+    if is_let_chain(cx.tcx, pat_id) {
+        return;
+    }
+
     let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
     let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
 
@@ -764,8 +769,11 @@ pub enum LetSource {
 
 fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
     let hir = tcx.hir();
+
     let parent = hir.get_parent_node(pat_id);
-    match hir.get(parent) {
+    let parent_node = hir.get(parent);
+
+    match parent_node {
         hir::Node::Arm(hir::Arm {
             guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
             ..
@@ -780,6 +788,7 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         }
         _ => {}
     }
+
     let parent_parent = hir.get_parent_node(parent);
     let parent_parent_node = hir.get(parent_parent);
 
@@ -792,12 +801,30 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         ..
     }) = parent_parent_parent_parent_node
     {
-        LetSource::WhileLet
-    } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) =
-        parent_parent_node
-    {
-        LetSource::IfLet
-    } else {
-        LetSource::GenericLet
+        return LetSource::WhileLet;
+    }
+
+    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node {
+        return LetSource::IfLet;
     }
+
+    LetSource::GenericLet
+}
+
+// Since this function is called within a let context, it is reasonable to assume that any parent
+// `&&` infers a let chain
+fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool {
+    let hir = tcx.hir();
+    let parent = hir.get_parent_node(pat_id);
+    let parent_parent = hir.get_parent_node(parent);
+    matches!(
+        hir.get(parent_parent),
+        hir::Node::Expr(
+            hir::Expr {
+                kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..),
+                ..
+            },
+            ..
+        )
+    )
 }
diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.rs b/src/test/ui/expr/if/attrs/let-chains-attr.rs
index 5237a9ff3961a..2cd8731141af7 100644
--- a/src/test/ui/expr/if/attrs/let-chains-attr.rs
+++ b/src/test/ui/expr/if/attrs/let-chains-attr.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
+#![feature(let_chains)]
 
 #[cfg(FALSE)]
 fn foo() {
diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.stderr b/src/test/ui/expr/if/attrs/let-chains-attr.stderr
deleted file mode 100644
index 8b9874715342c..0000000000000
--- a/src/test/ui/expr/if/attrs/let-chains-attr.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/let-chains-attr.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs
new file mode 100644
index 0000000000000..01f943c87dd7f
--- /dev/null
+++ b/src/test/ui/mir/mir_let_chains_drop_order.rs
@@ -0,0 +1,93 @@
+// run-pass
+// needs-unwind
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// See `mir_drop_order.rs` for more information
+
+#![feature(let_chains)]
+
+use std::cell::RefCell;
+use std::panic;
+
+pub struct DropLogger<'a, T> {
+    extra: T,
+    id: usize,
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
+}
+
+impl<'a, T> Drop for DropLogger<'a, T> {
+    fn drop(&mut self) {
+        self.log.0.borrow_mut().push(self.id);
+    }
+}
+
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
+fn main() {
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
+    let d = |id, extra| DropLogger { extra, id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.0.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (
+            d(
+                0,
+                d(
+                    1,
+                    if let Some(_) = d(2, Some(true)).extra && let DropLogger { .. } = d(3, None) {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(4, None),
+            &d(5, None),
+            d(6, None),
+            if let DropLogger { .. } = d(7, None) && let DropLogger { .. } = d(8, None) {
+                d(9, None)
+            }
+            else {
+                // 10 is not constructed
+                d(10, None)
+            }
+        );
+        assert_eq!(get(), vec![3, 8, 7, 1, 2]);
+    }
+    assert_eq!(get(), vec![0, 4, 6, 9, 5]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (
+            d(
+                11,
+                d(
+                    12,
+                    if let Some(_) = d(13, Some(true)).extra
+                        && let DropLogger { .. } = d(14, None)
+                    {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(15, None),
+            &d(16, None),
+            d(17, None),
+            if let DropLogger { .. } = d(18, None) && let DropLogger { .. } = d(19, None) {
+                d(20, None)
+            }
+            else {
+                // 10 is not constructed
+                d(21, None)
+            },
+            panic::panic_any(InjectedFailure)
+        );
+    });
+    assert_eq!(get(), vec![14, 19, 20, 17, 15, 11, 18, 16, 12, 13]);
+}
diff --git a/src/test/ui/pattern/issue-82290.rs b/src/test/ui/pattern/issue-82290.rs
deleted file mode 100644
index d8da0ac8aa6c5..0000000000000
--- a/src/test/ui/pattern/issue-82290.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
-
-fn main() {
-    if true && let x = 1 { //~ WARN irrefutable `let` pattern
-        let _ = x;
-    }
-}
diff --git a/src/test/ui/pattern/issue-82290.stderr b/src/test/ui/pattern/issue-82290.stderr
deleted file mode 100644
index 0a3cf2c794f47..0000000000000
--- a/src/test/ui/pattern/issue-82290.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-82290.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: irrefutable `let` pattern
-  --> $DIR/issue-82290.rs:6:16
-   |
-LL |     if true && let x = 1 {
-   |                ^^^^^^^^^
-   |
-   = note: `#[warn(irrefutable_let_patterns)]` on by default
-   = note: this pattern will always match, so the `let` is useless
-   = help: consider removing `let`
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
index 2a2c0be52630b..34d2d84da934f 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
@@ -8,36 +8,36 @@ fn _if_let_guard() {
         //~^ ERROR `if let` guards are experimental
 
         () if (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (((let 0 = 1))) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && let 0 = 1 => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
         _ => {}
     }
 }
@@ -52,9 +52,9 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     match () {
         #[cfg(FALSE)]
         () if let 0 = 1 => {}
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
index bedcdcb019ba9..0cda6ba9a9927 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
@@ -27,7 +27,7 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:10:16
    |
 LL |         () if (let 0 = 1) => {}
@@ -35,9 +35,8 @@ LL |         () if (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:13:18
    |
 LL |         () if (((let 0 = 1))) => {}
@@ -45,9 +44,8 @@ LL |         () if (((let 0 = 1))) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:16:23
    |
 LL |         () if true && let 0 = 1 => {}
@@ -55,9 +53,8 @@ LL |         () if true && let 0 = 1 => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:19:15
    |
 LL |         () if let 0 = 1 && true => {}
@@ -65,9 +62,8 @@ LL |         () if let 0 = 1 && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:22:16
    |
 LL |         () if (let 0 = 1) && true => {}
@@ -75,9 +71,8 @@ LL |         () if (let 0 = 1) && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:25:24
    |
 LL |         () if true && (let 0 = 1) => {}
@@ -85,9 +80,8 @@ LL |         () if true && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -95,9 +89,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -105,9 +98,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:15
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -115,9 +107,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:28
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -125,9 +116,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -135,9 +125,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -145,9 +134,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -155,9 +143,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:39:15
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
@@ -165,9 +152,8 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:54:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -175,9 +161,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -185,7 +170,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 19 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
new file mode 100644
index 0000000000000..708bcdd0aefe3
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let first = Some(1);
+    let second = Some(2);
+    let mut n = 0;
+    if let x = first && let y = second && 1 == 1 {
+        assert_eq!(x, first);
+        assert_eq!(y, second);
+        n = 1;
+    }
+    assert_eq!(n, 1);
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
index 710fdd57ed7b3..69bc189dd3579 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() {
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
index 6052ea95d0f85..e737ef26e9b38 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
@@ -4,7 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() { if let 0 = 1 {} }
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
new file mode 100644
index 0000000000000..a7e108d72d1ff
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
@@ -0,0 +1,20 @@
+fn and_chain() {
+    let z;
+    if true && { z = 3; true} && z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn and_chain_2() {
+    let z;
+    true && { z = 3; true} && z == 3;
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn or_chain() {
+    let z;
+    if false || { z = 3; false} || z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
new file mode 100644
index 0000000000000..3c47040cc8c24
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
@@ -0,0 +1,21 @@
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:3:34
+   |
+LL |     if true && { z = 3; true} && z == 3 {}
+   |                                  ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:9:31
+   |
+LL |     true && { z = 3; true} && z == 3;
+   |                               ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:15:36
+   |
+LL |     if false || { z = 3; false} || z == 3 {}
+   |                                    ^ use of possibly-uninitialized `z`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index b0b3464c61017..5b2693d07a790 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -18,7 +18,6 @@
 // To that end, we check some positions which is not part of the language above.
 
 #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-//~^ WARN the feature `let_chains` is incomplete
 
 #![allow(irrefutable_let_patterns)]
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 1433a16d7274a..4c830554d435c 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:233:9
+  --> $DIR/disallowed-positions.rs:232:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:30:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -19,7 +19,7 @@ LL |     if &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     if !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:34:9
+  --> $DIR/disallowed-positions.rs:33:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     if *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:36:9
+  --> $DIR/disallowed-positions.rs:35:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -46,7 +46,7 @@ LL |     if -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:44:9
+  --> $DIR/disallowed-positions.rs:43:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -55,7 +55,7 @@ LL |     if (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:48:16
+  --> $DIR/disallowed-positions.rs:47:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     if true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:17
+  --> $DIR/disallowed-positions.rs:48:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     if (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:50:25
+  --> $DIR/disallowed-positions.rs:49:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -82,7 +82,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:51:25
+  --> $DIR/disallowed-positions.rs:50:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:54:12
+  --> $DIR/disallowed-positions.rs:53:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     if x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:57:15
+  --> $DIR/disallowed-positions.rs:56:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     if true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:59:11
+  --> $DIR/disallowed-positions.rs:58:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -118,7 +118,7 @@ LL |     if ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:61:9
+  --> $DIR/disallowed-positions.rs:60:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -127,7 +127,7 @@ LL |     if (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:90:19
+  --> $DIR/disallowed-positions.rs:89:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL |     if let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:94:12
+  --> $DIR/disallowed-positions.rs:93:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     while &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:12
+  --> $DIR/disallowed-positions.rs:96:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -190,7 +190,7 @@ LL |     while !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:98:12
+  --> $DIR/disallowed-positions.rs:97:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -199,7 +199,7 @@ LL |     while *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:100:12
+  --> $DIR/disallowed-positions.rs:99:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -208,7 +208,7 @@ LL |     while -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:108:12
+  --> $DIR/disallowed-positions.rs:107:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -217,7 +217,7 @@ LL |     while (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:112:19
+  --> $DIR/disallowed-positions.rs:111:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
@@ -226,7 +226,7 @@ LL |     while true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:113:20
+  --> $DIR/disallowed-positions.rs:112:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -235,7 +235,7 @@ LL |     while (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:28
+  --> $DIR/disallowed-positions.rs:113:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:115:28
+  --> $DIR/disallowed-positions.rs:114:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:118:15
+  --> $DIR/disallowed-positions.rs:117:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -262,7 +262,7 @@ LL |     while x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:121:18
+  --> $DIR/disallowed-positions.rs:120:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     while true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:123:14
+  --> $DIR/disallowed-positions.rs:122:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -280,7 +280,7 @@ LL |     while ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:125:12
+  --> $DIR/disallowed-positions.rs:124:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -289,7 +289,7 @@ LL |     while (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -298,7 +298,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -307,7 +307,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -316,7 +316,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:154:22
+  --> $DIR/disallowed-positions.rs:153:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -334,7 +334,7 @@ LL |     while let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:168:6
+  --> $DIR/disallowed-positions.rs:167:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -343,7 +343,7 @@ LL |     &let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:6
+  --> $DIR/disallowed-positions.rs:169:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -352,7 +352,7 @@ LL |     !let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:171:6
+  --> $DIR/disallowed-positions.rs:170:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -361,7 +361,7 @@ LL |     *let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:173:6
+  --> $DIR/disallowed-positions.rs:172:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -370,7 +370,7 @@ LL |     -let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:6
+  --> $DIR/disallowed-positions.rs:180:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
@@ -379,7 +379,7 @@ LL |     (let 0 = 0)?;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:185:13
+  --> $DIR/disallowed-positions.rs:184:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
@@ -388,7 +388,7 @@ LL |     true || let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:186:14
+  --> $DIR/disallowed-positions.rs:185:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
@@ -397,7 +397,7 @@ LL |     (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:187:22
+  --> $DIR/disallowed-positions.rs:186:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
@@ -406,7 +406,7 @@ LL |     true && (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:190:9
+  --> $DIR/disallowed-positions.rs:189:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -415,7 +415,7 @@ LL |     x = let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:192:12
+  --> $DIR/disallowed-positions.rs:191:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
@@ -424,7 +424,7 @@ LL |     true..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:193:8
+  --> $DIR/disallowed-positions.rs:192:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
@@ -433,7 +433,7 @@ LL |     ..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:194:6
+  --> $DIR/disallowed-positions.rs:193:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
@@ -442,7 +442,7 @@ LL |     (let 0 = 0)..;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:196:6
+  --> $DIR/disallowed-positions.rs:195:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:200:6
+  --> $DIR/disallowed-positions.rs:199:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -460,7 +460,7 @@ LL |     (let true = let true = true);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:204:6
+  --> $DIR/disallowed-positions.rs:203:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -469,7 +469,7 @@ LL |     &let 0 = 0
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:215:17
+  --> $DIR/disallowed-positions.rs:214:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -478,7 +478,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:219:17
+  --> $DIR/disallowed-positions.rs:218:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -487,7 +487,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:17
+  --> $DIR/disallowed-positions.rs:222:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -496,7 +496,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:233:17
+  --> $DIR/disallowed-positions.rs:232:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -504,17 +504,8 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/disallowed-positions.rs:20:12
-   |
-LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:30:8
+  --> $DIR/disallowed-positions.rs:29:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -526,19 +517,19 @@ LL +     if let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:34:8
+  --> $DIR/disallowed-positions.rs:33:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:36:8
+  --> $DIR/disallowed-positions.rs:35:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:44:8
+  --> $DIR/disallowed-positions.rs:43:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -546,7 +537,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:44:19
+  --> $DIR/disallowed-positions.rs:43:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -563,7 +554,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:54:8
+  --> $DIR/disallowed-positions.rs:53:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -574,7 +565,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:57:8
+  --> $DIR/disallowed-positions.rs:56:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -583,7 +574,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:59:8
+  --> $DIR/disallowed-positions.rs:58:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -592,7 +583,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:61:8
+  --> $DIR/disallowed-positions.rs:60:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -601,7 +592,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -612,7 +603,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -621,7 +612,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:12
+  --> $DIR/disallowed-positions.rs:68:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -632,7 +623,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -641,7 +632,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -652,16 +643,16 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:41
+  --> $DIR/disallowed-positions.rs:75:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:76:41: 76:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -670,7 +661,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:12
+  --> $DIR/disallowed-positions.rs:83:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -681,13 +672,13 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:44
+  --> $DIR/disallowed-positions.rs:83:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -696,7 +687,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:40:20
+  --> $DIR/disallowed-positions.rs:39:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -704,7 +695,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:94:11
+  --> $DIR/disallowed-positions.rs:93:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -716,19 +707,19 @@ LL +     while let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:98:11
+  --> $DIR/disallowed-positions.rs:97:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:100:11
+  --> $DIR/disallowed-positions.rs:99:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:108:11
+  --> $DIR/disallowed-positions.rs:107:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -736,7 +727,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:108:22
+  --> $DIR/disallowed-positions.rs:107:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -753,7 +744,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:118:11
+  --> $DIR/disallowed-positions.rs:117:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -764,7 +755,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:121:11
+  --> $DIR/disallowed-positions.rs:120:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -773,7 +764,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:123:11
+  --> $DIR/disallowed-positions.rs:122:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -782,7 +773,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:125:11
+  --> $DIR/disallowed-positions.rs:124:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -791,7 +782,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:15
+  --> $DIR/disallowed-positions.rs:128:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -802,7 +793,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -811,7 +802,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:15
+  --> $DIR/disallowed-positions.rs:132:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -822,7 +813,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -831,7 +822,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:15
+  --> $DIR/disallowed-positions.rs:139:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -842,16 +833,16 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:44
+  --> $DIR/disallowed-positions.rs:139:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:140:44: 140:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -860,7 +851,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:15
+  --> $DIR/disallowed-positions.rs:147:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -871,13 +862,13 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:47
+  --> $DIR/disallowed-positions.rs:147:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -886,7 +877,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:104:23
+  --> $DIR/disallowed-positions.rs:103:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -894,19 +885,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:171:5
+  --> $DIR/disallowed-positions.rs:170:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:173:5
+  --> $DIR/disallowed-positions.rs:172:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:181:5
+  --> $DIR/disallowed-positions.rs:180:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -914,7 +905,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:181:16
+  --> $DIR/disallowed-positions.rs:180:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -931,7 +922,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:196:10
+  --> $DIR/disallowed-positions.rs:195:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -942,7 +933,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:204:5
+  --> $DIR/disallowed-positions.rs:203:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -951,14 +942,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:177:17
+  --> $DIR/disallowed-positions.rs:176:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 103 previous errors; 1 warning emitted
+error: aborting due to 103 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
index 2b4259e9dc150..53fec8316e7e7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
@@ -12,79 +12,79 @@ fn _if() {
     if let 0 = 1 {} // Stable!
 
     if (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _while() {
     while let 0 = 1 {} // Stable!
 
     while (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _macros() {
     macro_rules! noop_expr { ($e:expr) => {}; }
 
     noop_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     macro_rules! use_expr {
         ($e:expr) => {
@@ -93,11 +93,11 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     #[cfg(FALSE)] (let 0 = 1);
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!(let 0 = 1);
     //~^ ERROR no rules expected the token `let`
     // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
index 180eee0cadfe6..458826498fe2d 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
@@ -7,7 +7,7 @@ LL |     macro_rules! use_expr {
 LL |     use_expr!(let 0 = 1);
    |               ^^^ no rules expected this token in macro call
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:14:9
    |
 LL |     if (let 0 = 1) {}
@@ -15,9 +15,8 @@ LL |     if (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:17:11
    |
 LL |     if (((let 0 = 1))) {}
@@ -25,9 +24,8 @@ LL |     if (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:20:16
    |
 LL |     if true && let 0 = 1 {}
@@ -35,9 +33,8 @@ LL |     if true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:23:8
    |
 LL |     if let 0 = 1 && true {}
@@ -45,9 +42,8 @@ LL |     if let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:26:9
    |
 LL |     if (let 0 = 1) && true {}
@@ -55,9 +51,8 @@ LL |     if (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:29:17
    |
 LL |     if true && (let 0 = 1) {}
@@ -65,9 +60,8 @@ LL |     if true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -75,9 +69,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -85,9 +78,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:8
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -95,9 +87,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:21
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -105,9 +96,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -115,9 +105,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -125,9 +114,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -135,9 +123,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:43:8
    |
 LL |     if let Range { start: _, end: _ } = (true..true) && false {}
@@ -145,9 +132,8 @@ LL |     if let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:50:12
    |
 LL |     while (let 0 = 1) {}
@@ -155,9 +141,8 @@ LL |     while (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:53:14
    |
 LL |     while (((let 0 = 1))) {}
@@ -165,9 +150,8 @@ LL |     while (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:19
    |
 LL |     while true && let 0 = 1 {}
@@ -175,9 +159,8 @@ LL |     while true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:59:11
    |
 LL |     while let 0 = 1 && true {}
@@ -185,9 +168,8 @@ LL |     while let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:62:12
    |
 LL |     while (let 0 = 1) && true {}
@@ -195,9 +177,8 @@ LL |     while (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:65:20
    |
 LL |     while true && (let 0 = 1) {}
@@ -205,9 +186,8 @@ LL |     while true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -215,9 +195,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -225,9 +204,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:11
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -235,9 +213,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:24
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -245,9 +222,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -255,9 +231,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -265,9 +240,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -275,9 +249,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:79:11
    |
 LL |     while let Range { start: _, end: _ } = (true..true) && false {}
@@ -285,9 +258,8 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:99:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
@@ -295,9 +267,8 @@ LL |     #[cfg(FALSE)] (let 0 = 1);
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:86:17
    |
 LL |     noop_expr!((let 0 = 1));
@@ -305,9 +276,8 @@ LL |     noop_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:95:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -315,9 +285,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:97:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -325,7 +294,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 33 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
new file mode 100644
index 0000000000000..5915cb9df269c
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+#![feature(let_chains)]
+
+use std::ops::Range;
+
+fn main() {
+    let opt = Some(None..Some(1));
+
+    if let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    if let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    if let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+
+    while let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    while let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    while let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
new file mode 100644
index 0000000000000..3eb8a9ad06020
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+pub enum UnOp {
+    Not(Vec<()>),
+}
+
+pub fn foo() {
+    if let Some(x) = None {
+        match x {
+            UnOp::Not(_) => {}
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
new file mode 100644
index 0000000000000..6b7d883565085
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let x = Some(vec!["test"]);
+
+    if let Some(v) = x && v.is_empty() {
+        println!("x == Some([])");
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
new file mode 100644
index 0000000000000..7c7e31f4db400
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let opt = Some("foo bar");
+
+    if true && let Some(x) = opt {
+        println!("{}", x);
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
new file mode 100644
index 0000000000000..6b91c455e0e97
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    loop {
+        // [1][0] should leave top scope
+        if true && [1][0] == 1 && true {
+        }
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
new file mode 100644
index 0000000000000..0856a10520636
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
@@ -0,0 +1,35 @@
+// run-pass
+
+#![feature(let_chains)]
+
+fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    if let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        true
+    }
+    else {
+        false
+    }
+}
+
+fn check_while_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    while let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        return true;
+    }
+    false
+}
+
+fn main() {
+    assert_eq!(check_if_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_if_let(Some(Some(Some(1))), 9), false);
+
+    assert_eq!(check_while_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_while_let(Some(Some(Some(1))), 9), false);
+}