about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-01-19 10:42:12 +0100
committerGitHub <noreply@github.com>2022-01-19 10:42:12 +0100
commit5d2928f7b9eaea9c00ed7695143c0f71c5f53786 (patch)
treef0a6bf47736688b4369e06ae846220a88d43a62a
parent2f004d2d401682e553af3984ebd9a3976885e752 (diff)
parent5f74ef4fb1d86d80a3052e772010e613353dbfa7 (diff)
downloadrust-5d2928f7b9eaea9c00ed7695143c0f71c5f53786.tar.gz
rust-5d2928f7b9eaea9c00ed7695143c0f71c5f53786.zip
Rollup merge of #88642 - c410-f3r:let_chains_2, r=matthewjasper
Formally implement let chains

## Let chains

My longest and hardest contribution since #64010.

Thanks to `@Centril` for creating the RFC and special thanks to `@matthewjasper` for helping me since the beginning of this journey. In fact, `@matthewjasper` did much of the complicated MIR stuff so it's true to say that this feature wouldn't be possible without him. Thanks again `@matthewjasper!`

With the changes proposed in this PR, it will be possible to chain let expressions along side local variable declarations or ordinary conditional expressions. In other words, do much of what the `if_chain` crate already does.

## Other considerations

* `if let guard` and `let ... else` features need special care and should be handled in a following PR.

* Irrefutable patterns are allowed within a let chain context

* ~~Three Clippy lints were already converted to start dogfooding and help detect possible corner cases~~

cc #53667
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs18
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs19
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs43
-rw-r--r--src/test/ui/expr/if/attrs/let-chains-attr.rs2
-rw-r--r--src/test/ui/expr/if/attrs/let-chains-attr.stderr11
-rw-r--r--src/test/ui/mir/mir_let_chains_drop_order.rs93
-rw-r--r--src/test/ui/pattern/issue-82290.rs9
-rw-r--r--src/test/ui/pattern/issue-82290.stderr21
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.rs32
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr48
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs15
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs20
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr21
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs1
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr221
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.rs64
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr96
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs27
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-88498.rs16
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-90722.rs11
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-92145.rs11
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs9
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs35
31 files changed, 536 insertions, 340 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 470e9114217..6c172d59f83 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 89671788255..a6ecfa45206 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 47010ea3ab6..0b65a5ff3ec 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 eef42666f2a..11dc69ab715 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 43060ecfced..da8fbdbf3bc 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 e3a05e01ea8..85950d82419 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 fc46c54c2fc..84d6c1d2db8 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 750677f161e..a43388808cd 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 868dd195f3a..34204c3852a 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 5237a9ff396..2cd8731141a 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 8b987471534..00000000000
--- 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 00000000000..01f943c87dd
--- /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 d8da0ac8aa6..00000000000
--- 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 0a3cf2c794f..00000000000
--- 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 2a2c0be5263..34d2d84da93 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 bedcdcb019b..0cda6ba9a99 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 00000000000..708bcdd0aef
--- /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 710fdd57ed7..69bc189dd35 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 6052ea95d0f..e737ef26e9b 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 00000000000..a7e108d72d1
--- /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 00000000000..3c47040cc8c
--- /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 b0b3464c610..5b2693d07a7 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 1433a16d727..4c830554d43 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 2b4259e9dc1..53fec8316e7 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 180eee0cadf..458826498fe 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 00000000000..5915cb9df26
--- /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 00000000000..3eb8a9ad060
--- /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 00000000000..6b7d8835650
--- /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 00000000000..7c7e31f4db4
--- /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 00000000000..6b91c455e0e
--- /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 00000000000..0856a105206
--- /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);
+}