about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs83
-rw-r--r--tests/mir-opt/building/logical_or_in_conditional.rs2
-rw-r--r--tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir34
-rw-r--r--tests/ui/deriving/auxiliary/malicious-macro.rs2
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.fixed2
-rw-r--r--tests/ui/drop/drop-order-comparisons.rs2
-rw-r--r--tests/ui/drop/drop_order.rs3
-rw-r--r--tests/ui/drop/drop_order_if_let_rescope.rs4
-rw-r--r--tests/ui/drop/issue-100276.rs7
-rw-r--r--tests/ui/expr/if/attrs/let-chains-attr.rs3
-rw-r--r--tests/ui/lint/issue-121070-let-range.rs2
-rw-r--r--tests/ui/mir/issue-99852.rs2
-rw-r--r--tests/ui/mir/mir_let_chains_drop_order.rs2
-rw-r--r--tests/ui/parser/brace-in-let-chain.rs2
-rw-r--r--tests/ui/parser/deli-ident-issue-1.rs2
-rw-r--r--tests/ui/parser/issues/issue-103381.fixed2
-rw-r--r--tests/ui/parser/issues/issue-103381.rs2
-rw-r--r--tests/ui/parser/semi-in-let-chain.rs3
-rw-r--r--tests/ui/parser/semi-in-let-chain.stderr12
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs5
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr100
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs1
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs26
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs26
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr65
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr45
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs30
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs76
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs3
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs3
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs1
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr12
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs3
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs1
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.rs1
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.stdout1
-rw-r--r--tests/ui/unpretty/expanded-interpolation.rs3
-rw-r--r--tests/ui/unpretty/expanded-interpolation.stdout6
46 files changed, 411 insertions, 184 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 11e60175a1f..f3ed798eba4 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -26,6 +26,7 @@ use rustc_macros::Subdiagnostic;
 use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
+use rustc_span::edition::Edition;
 use rustc_span::source_map::{self, Spanned};
 use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Symbol, kw, sym};
 use thin_vec::{ThinVec, thin_vec};
@@ -2602,7 +2603,10 @@ impl<'a> Parser<'a> {
     /// Parses an `if` expression (`if` token already eaten).
     fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
-        let cond = self.parse_expr_cond()?;
+        // Scoping code checks the top level edition of the `if`; let's match it here.
+        // The `CondChecker` also checks the edition of the `let` itself, just to make sure.
+        let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
+        let cond = self.parse_expr_cond(let_chains_policy)?;
         self.parse_if_after_cond(lo, cond)
     }
 
@@ -2711,18 +2715,17 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses the condition of a `if` or `while` expression.
+    ///
+    /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
+    /// i.e. the same span we use to later decide whether the drop behaviour should be that of
+    /// edition `..=2021` or that of `2024..`.
     // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
-    pub fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
+    pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_outer_attributes()?;
         let (mut cond, _) =
             self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
 
-        CondChecker::new(self).visit_expr(&mut cond);
-
-        if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind {
-            // Remove the last feature gating of a `let` expression since it's stable.
-            self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
-        }
+        CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
 
         Ok(cond)
     }
@@ -3017,7 +3020,8 @@ impl<'a> Parser<'a> {
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
     fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
-        let cond = self.parse_expr_cond().map_err(|mut err| {
+        let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
+        let cond = self.parse_expr_cond(policy).map_err(|mut err| {
             err.span_label(lo, "while parsing the condition of this `while` expression");
             err
         })?;
@@ -3401,17 +3405,17 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
-        // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
+        // Used to check the `if_let_guard` feature mostly by scanning
         // `&&` tokens.
-        fn check_let_expr(expr: &Expr) -> (bool, bool) {
+        fn has_let_expr(expr: &Expr) -> bool {
             match &expr.kind {
                 ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
-                    let lhs_rslt = check_let_expr(lhs);
-                    let rhs_rslt = check_let_expr(rhs);
-                    (lhs_rslt.0 || rhs_rslt.0, false)
+                    let lhs_rslt = has_let_expr(lhs);
+                    let rhs_rslt = has_let_expr(rhs);
+                    lhs_rslt || rhs_rslt
                 }
-                ExprKind::Let(..) => (true, true),
-                _ => (false, true),
+                ExprKind::Let(..) => true,
+                _ => false,
             }
         }
         if !self.eat_keyword(exp!(If)) {
@@ -3422,14 +3426,9 @@ impl<'a> Parser<'a> {
         let if_span = self.prev_token.span;
         let mut cond = self.parse_match_guard_condition()?;
 
-        CondChecker::new(self).visit_expr(&mut cond);
+        CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
 
-        let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
-        if has_let_expr {
-            if does_not_have_bin_op {
-                // Remove the last feature gating of a `let` expression since it's stable.
-                self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
-            }
+        if has_let_expr(&cond) {
             let span = if_span.to(cond.span);
             self.psess.gated_spans.gate(sym::if_let_guard, span);
         }
@@ -3456,7 +3455,7 @@ impl<'a> Parser<'a> {
                     unreachable!()
                 };
                 self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
-                CondChecker::new(self).visit_expr(&mut cond);
+                CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
                 let right = self.prev_token.span;
                 self.dcx().emit_err(errors::ParenthesesInMatchPat {
                     span: vec![left, right],
@@ -4027,7 +4026,14 @@ pub(crate) enum ForbiddenLetReason {
     NotSupportedParentheses(#[primary_span] Span),
 }
 
-/// Visitor to check for invalid/unstable use of `ExprKind::Let` that can't
+/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
+/// 2024 and later). In case of edition dependence, specify the currently present edition.
+pub enum LetChainsPolicy {
+    AlwaysAllowed,
+    EditionDependent { current_edition: Edition },
+}
+
+/// Visitor to check for invalid use of `ExprKind::Let` that can't
 /// easily be caught in parsing. For example:
 ///
 /// ```rust,ignore (example)
@@ -4038,19 +4044,29 @@ pub(crate) enum ForbiddenLetReason {
 /// ```
 struct CondChecker<'a> {
     parser: &'a Parser<'a>,
+    let_chains_policy: LetChainsPolicy,
+    depth: u32,
     forbid_let_reason: Option<ForbiddenLetReason>,
     missing_let: Option<errors::MaybeMissingLet>,
     comparison: Option<errors::MaybeComparison>,
 }
 
 impl<'a> CondChecker<'a> {
-    fn new(parser: &'a Parser<'a>) -> Self {
-        CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None }
+    fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
+        CondChecker {
+            parser,
+            forbid_let_reason: None,
+            missing_let: None,
+            comparison: None,
+            let_chains_policy,
+            depth: 0,
+        }
     }
 }
 
 impl MutVisitor for CondChecker<'_> {
     fn visit_expr(&mut self, e: &mut P<Expr>) {
+        self.depth += 1;
         use ForbiddenLetReason::*;
 
         let span = e.span;
@@ -4065,8 +4081,16 @@ impl MutVisitor for CondChecker<'_> {
                             comparison: self.comparison,
                         },
                     ));
-                } else {
-                    self.parser.psess.gated_spans.gate(sym::let_chains, span);
+                } else if self.depth > 1 {
+                    // Top level `let` is always allowed; only gate chains
+                    match self.let_chains_policy {
+                        LetChainsPolicy::AlwaysAllowed => (),
+                        LetChainsPolicy::EditionDependent { current_edition } => {
+                            if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
+                                self.parser.psess.gated_spans.gate(sym::let_chains, span);
+                            }
+                        }
+                    }
                 }
             }
             ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
@@ -4168,5 +4192,6 @@ impl MutVisitor for CondChecker<'_> {
                 // These would forbid any let expressions they contain already.
             }
         }
+        self.depth -= 1;
     }
 }
diff --git a/tests/mir-opt/building/logical_or_in_conditional.rs b/tests/mir-opt/building/logical_or_in_conditional.rs
index e6872e6f2ec..249ccf72804 100644
--- a/tests/mir-opt/building/logical_or_in_conditional.rs
+++ b/tests/mir-opt/building/logical_or_in_conditional.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 //@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ edition: 2024
 struct Droppy(u8);
 impl Drop for Droppy {
     fn drop(&mut self) {
diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
index 72bd4605b26..327b3b618a0 100644
--- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
+++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
@@ -19,7 +19,7 @@ fn test_complex() -> () {
     bb0: {
         StorageLive(_1);
         StorageLive(_2);
-        _2 = E::f() -> [return: bb1, unwind: bb34];
+        _2 = E::f() -> [return: bb1, unwind: bb35];
     }
 
     bb1: {
@@ -42,7 +42,7 @@ fn test_complex() -> () {
 
     bb5: {
         StorageLive(_4);
-        _4 = always_true() -> [return: bb6, unwind: bb34];
+        _4 = always_true() -> [return: bb6, unwind: bb35];
     }
 
     bb6: {
@@ -64,7 +64,7 @@ fn test_complex() -> () {
     }
 
     bb9: {
-        drop(_7) -> [return: bb11, unwind: bb34];
+        drop(_7) -> [return: bb11, unwind: bb35];
     }
 
     bb10: {
@@ -78,7 +78,7 @@ fn test_complex() -> () {
     }
 
     bb12: {
-        drop(_7) -> [return: bb13, unwind: bb34];
+        drop(_7) -> [return: bb13, unwind: bb35];
     }
 
     bb13: {
@@ -98,7 +98,7 @@ fn test_complex() -> () {
     }
 
     bb15: {
-        drop(_10) -> [return: bb17, unwind: bb34];
+        drop(_10) -> [return: bb17, unwind: bb35];
     }
 
     bb16: {
@@ -113,11 +113,12 @@ fn test_complex() -> () {
 
     bb18: {
         _1 = const ();
+        StorageDead(_2);
         goto -> bb22;
     }
 
     bb19: {
-        drop(_10) -> [return: bb20, unwind: bb34];
+        drop(_10) -> [return: bb20, unwind: bb35];
     }
 
     bb20: {
@@ -127,6 +128,7 @@ fn test_complex() -> () {
     }
 
     bb21: {
+        StorageDead(_2);
         _1 = const ();
         goto -> bb22;
     }
@@ -135,10 +137,9 @@ fn test_complex() -> () {
         StorageDead(_8);
         StorageDead(_5);
         StorageDead(_4);
-        StorageDead(_2);
         StorageDead(_1);
         StorageLive(_11);
-        _11 = always_true() -> [return: bb23, unwind: bb34];
+        _11 = always_true() -> [return: bb23, unwind: bb35];
     }
 
     bb23: {
@@ -146,7 +147,7 @@ fn test_complex() -> () {
     }
 
     bb24: {
-        goto -> bb32;
+        goto -> bb33;
     }
 
     bb25: {
@@ -155,7 +156,7 @@ fn test_complex() -> () {
 
     bb26: {
         StorageLive(_12);
-        _12 = E::f() -> [return: bb27, unwind: bb34];
+        _12 = E::f() -> [return: bb27, unwind: bb35];
     }
 
     bb27: {
@@ -178,21 +179,26 @@ fn test_complex() -> () {
 
     bb31: {
         _0 = const ();
-        goto -> bb33;
+        StorageDead(_12);
+        goto -> bb34;
     }
 
     bb32: {
-        _0 = const ();
+        StorageDead(_12);
         goto -> bb33;
     }
 
     bb33: {
+        _0 = const ();
+        goto -> bb34;
+    }
+
+    bb34: {
         StorageDead(_11);
-        StorageDead(_12);
         return;
     }
 
-    bb34 (cleanup): {
+    bb35 (cleanup): {
         resume;
     }
 }
diff --git a/tests/ui/deriving/auxiliary/malicious-macro.rs b/tests/ui/deriving/auxiliary/malicious-macro.rs
index 6665b40a14f..c551b3f927c 100644
--- a/tests/ui/deriving/auxiliary/malicious-macro.rs
+++ b/tests/ui/deriving/auxiliary/malicious-macro.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
 
 extern crate proc_macro;
 
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
index 78cf421cfbf..71158cb8062 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.fixed
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -24,7 +24,7 @@
 //@ [e2024] edition: 2024
 //@ run-pass
 
-#![feature(let_chains)]
+#![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
 fn t_bindings() {
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
index 78c75a9449f..0492b3a4db7 100644
--- a/tests/ui/drop/drop-order-comparisons.rs
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -24,7 +24,7 @@
 //@ [e2024] edition: 2024
 //@ run-pass
 
-#![feature(let_chains)]
+#![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
 fn t_bindings() {
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index d1a5b9bc5e2..b96e55a2535 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -2,9 +2,10 @@
 //@ compile-flags: -Z validate-mir
 //@ revisions: edition2021 edition2024
 //@ [edition2021] edition: 2021
+//@ [edition2024] compile-flags: -Z lint-mir
 //@ [edition2024] edition: 2024
 
-#![feature(let_chains)]
+#![cfg_attr(edition2021, feature(let_chains))]
 
 use std::cell::RefCell;
 use std::convert::TryInto;
diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs
index 7445e3a6a5f..27bced5fa62 100644
--- a/tests/ui/drop/drop_order_if_let_rescope.rs
+++ b/tests/ui/drop/drop_order_if_let_rescope.rs
@@ -1,8 +1,6 @@
 //@ run-pass
 //@ edition:2024
-//@ compile-flags: -Z validate-mir
-
-#![feature(let_chains)]
+//@ compile-flags: -Z validate-mir -Z lint-mir
 
 use std::cell::RefCell;
 use std::convert::TryInto;
diff --git a/tests/ui/drop/issue-100276.rs b/tests/ui/drop/issue-100276.rs
index b44710e7c3f..5d212b3a0a9 100644
--- a/tests/ui/drop/issue-100276.rs
+++ b/tests/ui/drop/issue-100276.rs
@@ -1,6 +1,11 @@
 //@ check-pass
 //@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] compile-flags: -Z lint-mir
+//@ [edition2024] edition: 2024
+
+#![cfg_attr(edition2021, feature(let_chains))]
 
 fn let_chains(entry: std::io::Result<std::fs::DirEntry>) {
     if let Ok(entry) = entry
diff --git a/tests/ui/expr/if/attrs/let-chains-attr.rs b/tests/ui/expr/if/attrs/let-chains-attr.rs
index 2cf1b169f06..7b74b17784e 100644
--- a/tests/ui/expr/if/attrs/let-chains-attr.rs
+++ b/tests/ui/expr/if/attrs/let-chains-attr.rs
@@ -1,6 +1,5 @@
 //@ check-pass
-
-#![feature(let_chains)]
+//@ edition:2024
 
 #[cfg(false)]
 fn foo() {
diff --git a/tests/ui/lint/issue-121070-let-range.rs b/tests/ui/lint/issue-121070-let-range.rs
index 1f575cfaca5..82878587f8d 100644
--- a/tests/ui/lint/issue-121070-let-range.rs
+++ b/tests/ui/lint/issue-121070-let-range.rs
@@ -1,6 +1,6 @@
 //@ check-pass
+//@ edition:2024
 
-#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 fn main() {
     let _a = 0..1;
diff --git a/tests/ui/mir/issue-99852.rs b/tests/ui/mir/issue-99852.rs
index 59459c67228..af754cf8546 100644
--- a/tests/ui/mir/issue-99852.rs
+++ b/tests/ui/mir/issue-99852.rs
@@ -1,6 +1,6 @@
 //@ check-pass
 //@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn lambda<T, U>() -> U
 where
diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs
index 8991c6db7b9..4794f3427dd 100644
--- a/tests/ui/mir/mir_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_let_chains_drop_order.rs
@@ -6,7 +6,7 @@
 
 // See `mir_drop_order.rs` for more information
 
-#![feature(let_chains)]
+#![cfg_attr(edition2021, feature(let_chains))]
 #![allow(irrefutable_let_patterns)]
 
 use std::cell::RefCell;
diff --git a/tests/ui/parser/brace-in-let-chain.rs b/tests/ui/parser/brace-in-let-chain.rs
index 2009bc88d9e..25586441c18 100644
--- a/tests/ui/parser/brace-in-let-chain.rs
+++ b/tests/ui/parser/brace-in-let-chain.rs
@@ -1,6 +1,6 @@
 // issue #117766
+//@ edition: 2024
 
-#![feature(let_chains)]
 fn main() {
     if let () = ()
         && let () = () {
diff --git a/tests/ui/parser/deli-ident-issue-1.rs b/tests/ui/parser/deli-ident-issue-1.rs
index 224ee6c09e0..b7e7df1f860 100644
--- a/tests/ui/parser/deli-ident-issue-1.rs
+++ b/tests/ui/parser/deli-ident-issue-1.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
 trait Demo {}
 
 impl dyn Demo {
diff --git a/tests/ui/parser/issues/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed
index 87c308789a1..955b246b863 100644
--- a/tests/ui/parser/issues/issue-103381.fixed
+++ b/tests/ui/parser/issues/issue-103381.fixed
@@ -1,6 +1,6 @@
+//@ edition: 2024
 //@ run-rustfix
 
-#![feature(let_chains)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 #![allow(irrefutable_let_patterns)]
diff --git a/tests/ui/parser/issues/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs
index ccbc40e5d02..d4b06b9c770 100644
--- a/tests/ui/parser/issues/issue-103381.rs
+++ b/tests/ui/parser/issues/issue-103381.rs
@@ -1,6 +1,6 @@
+//@ edition: 2024
 //@ run-rustfix
 
-#![feature(let_chains)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 #![allow(irrefutable_let_patterns)]
diff --git a/tests/ui/parser/semi-in-let-chain.rs b/tests/ui/parser/semi-in-let-chain.rs
index 9c21af0372d..522b90ea250 100644
--- a/tests/ui/parser/semi-in-let-chain.rs
+++ b/tests/ui/parser/semi-in-let-chain.rs
@@ -1,6 +1,5 @@
 // Issue #117720
-
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn main() {
     if let () = ()
diff --git a/tests/ui/parser/semi-in-let-chain.stderr b/tests/ui/parser/semi-in-let-chain.stderr
index c1a8f92965e..f36d5e041e5 100644
--- a/tests/ui/parser/semi-in-let-chain.stderr
+++ b/tests/ui/parser/semi-in-let-chain.stderr
@@ -1,11 +1,11 @@
 error: expected `{`, found `;`
-  --> $DIR/semi-in-let-chain.rs:7:23
+  --> $DIR/semi-in-let-chain.rs:6:23
    |
 LL |         && let () = ();
    |                       ^ expected `{`
    |
 note: you likely meant to continue parsing the let-chain starting here
-  --> $DIR/semi-in-let-chain.rs:8:9
+  --> $DIR/semi-in-let-chain.rs:7:9
    |
 LL |         && let () = ()
    |         ^^^^^^
@@ -16,13 +16,13 @@ LL +         && let () = ()
    |
 
 error: expected `{`, found `;`
-  --> $DIR/semi-in-let-chain.rs:15:20
+  --> $DIR/semi-in-let-chain.rs:14:20
    |
 LL |         && () == ();
    |                    ^ expected `{`
    |
 note: the `if` expression is missing a block after this condition
-  --> $DIR/semi-in-let-chain.rs:14:8
+  --> $DIR/semi-in-let-chain.rs:13:8
    |
 LL |       if let () = ()
    |  ________^
@@ -30,13 +30,13 @@ LL | |         && () == ();
    | |___________________^
 
 error: expected `{`, found `;`
-  --> $DIR/semi-in-let-chain.rs:23:20
+  --> $DIR/semi-in-let-chain.rs:22:20
    |
 LL |         && () == ();
    |                    ^ expected `{`
    |
 note: you likely meant to continue parsing the let-chain starting here
-  --> $DIR/semi-in-let-chain.rs:24:9
+  --> $DIR/semi-in-let-chain.rs:23:9
    |
 LL |         && let () = ()
    |         ^^^^^^
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
index 6b85ada3aad..60e5452edb3 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
@@ -1,5 +1,5 @@
+//@ edition: 2024
 #![feature(never_patterns)]
-#![feature(let_chains)]
 #![allow(incomplete_features)]
 #![deny(unreachable_patterns)]
 
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
index 983fe87451f..b1e305834cb 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
@@ -15,11 +15,9 @@ fn _if_let_guard() {
 
         () if true && let 0 = 1 => {}
         //~^ ERROR `if let` guards are experimental
-        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
         //~^ ERROR `if let` guards are experimental
-        //~| ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
         //~^ ERROR expected expression, found `let` statement
@@ -33,8 +31,6 @@ fn _if_let_guard() {
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
         //~^ ERROR `if let` guards are experimental
-        //~| ERROR `let` expressions in this position are unstable
-        //~| ERROR `let` expressions in this position are unstable
         //~| ERROR expected expression, found `let` statement
         //~| ERROR expected expression, found `let` statement
         //~| ERROR expected expression, found `let` statement
@@ -42,7 +38,6 @@ fn _if_let_guard() {
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
         //~^ ERROR `if let` guards are experimental
-        //~| ERROR `let` expressions in this position are unstable
 
         _ => {}
     }
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
index 0997f0c81a0..19d1f4b0a57 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
@@ -25,98 +25,98 @@ LL |         () if (((let 0 = 1))) => {}
    |                  ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:24:16
+  --> $DIR/feature-gate.rs:22:16
    |
 LL |         () if (let 0 = 1) && true => {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:24:16
+  --> $DIR/feature-gate.rs:22:16
    |
 LL |         () if (let 0 = 1) && true => {}
    |                ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:27:24
+  --> $DIR/feature-gate.rs:25:24
    |
 LL |         () if true && (let 0 = 1) => {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:27:24
+  --> $DIR/feature-gate.rs:25:24
    |
 LL |         () if true && (let 0 = 1) => {}
    |                        ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:30:16
+  --> $DIR/feature-gate.rs:28:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:30:16
+  --> $DIR/feature-gate.rs:28:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:30:31
+  --> $DIR/feature-gate.rs:28:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:30:31
+  --> $DIR/feature-gate.rs:28:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                               ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:34:42
+  --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:34:42
+  --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:34:55
+  --> $DIR/feature-gate.rs:32:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                       ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:34:42
+  --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:34:68
+  --> $DIR/feature-gate.rs:32:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/feature-gate.rs:34:42
+  --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:60:16
+  --> $DIR/feature-gate.rs:55:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -124,7 +124,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:60:16
+  --> $DIR/feature-gate.rs:55:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -133,7 +133,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:63:16
+  --> $DIR/feature-gate.rs:58:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -141,7 +141,7 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:63:16
+  --> $DIR/feature-gate.rs:58:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -150,7 +150,7 @@ LL |     use_expr!((let 0 = 1));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: no rules expected keyword `let`
-  --> $DIR/feature-gate.rs:72:15
+  --> $DIR/feature-gate.rs:67:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -159,7 +159,7 @@ LL |     use_expr!(let 0 = 1);
    |               ^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr`
-  --> $DIR/feature-gate.rs:53:10
+  --> $DIR/feature-gate.rs:48:10
    |
 LL |         ($e:expr) => {
    |          ^^^^^^^
@@ -187,7 +187,7 @@ LL |         () if true && let 0 = 1 => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:20:12
+  --> $DIR/feature-gate.rs:19:12
    |
 LL |         () if let 0 = 1 && true => {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +198,7 @@ LL |         () if let 0 = 1 && true => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:34:12
+  --> $DIR/feature-gate.rs:32:12
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:43:12
+  --> $DIR/feature-gate.rs:39:12
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:68:12
+  --> $DIR/feature-gate.rs:63:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -230,56 +230,6 @@ LL |         () if let 0 = 1 => {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:16:23
-   |
-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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:20:15
-   |
-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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:34:15
-   |
-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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:34:28
-   |
-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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:43:15
-   |
-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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 25 previous errors
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
index 423a2cd53fc..e1138835006 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
@@ -1,7 +1,6 @@
 // Expression macros can't expand to a let match guard.
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 
 macro_rules! m {
     ($e:expr) => { let Some(x) = $e }
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
index b8065b9f556..921cd083fff 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
@@ -1,5 +1,5 @@
 error: expected expression, found `let` statement
-  --> $DIR/macro-expanded.rs:7:20
+  --> $DIR/macro-expanded.rs:6:20
    |
 LL |     ($e:expr) => { let Some(x) = $e }
    |                    ^^^
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
index 47653efffb7..29f529a30c2 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
@@ -1,5 +1,5 @@
+//@ edition: 2024
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 fn same_pattern(c: bool) {
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
index 0e71a9d24c9..a4cb73c6508 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
@@ -1,7 +1,7 @@
+//@ edition: 2024
 // Parenthesised let "expressions" are not allowed in guards
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 
 #[cfg(false)]
 fn un_cfged() {
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
index 32a223c9159..e7946a2a23b 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
@@ -1,8 +1,8 @@
 // Check shadowing in if let guards works as expected.
 //@ check-pass
+//@ edition: 2024
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 
 fn main() {
     let x: Option<Option<i32>> = Some(Some(6));
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
index e1edde6de19..dc052c38fe7 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
@@ -1,6 +1,6 @@
 //@ run-pass
+//@ edition: 2024
 
-#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 fn main() {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
index cb3be59bee0..ae13f7c76ba 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn let_or_guard(x: Result<Option<i32>, ()>) {
     match x {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs
new file mode 100644
index 00000000000..d2d5ae11104
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs
@@ -0,0 +1,26 @@
+//@ edition: 2021
+
+#[macro_export]
+macro_rules! make_if {
+    (($($tt:tt)*) { $body:expr } { $else:expr }) => {{
+        if $($tt)* {
+            $body
+        } else {
+            $else
+        }
+    }};
+    (let ($expr:expr) { $body:expr } { $else:expr }) => {{
+        if let None = $expr {
+            $body
+        } else {
+            $else
+        }
+    }};
+    (let ($expr:expr) let ($expr2:expr) { $body:expr } { $else:expr }) => {{
+        if let None = $expr && let None = $expr2 {
+            $body
+        } else {
+            $else
+        }
+    }};
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs
new file mode 100644
index 00000000000..f5b6f35abf8
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs
@@ -0,0 +1,26 @@
+//@ edition: 2024
+
+#[macro_export]
+macro_rules! make_if {
+    (($($tt:tt)*) { $body:expr } { $else:expr }) => {{
+        if $($tt)* {
+            $body
+        } else {
+            $else
+        }
+    }};
+    (let ($expr:expr) { $body:expr } { $else:expr }) => {{
+        if let None = $expr {
+            $body
+        } else {
+            $else
+        }
+    }};
+    (let ($expr:expr) let ($expr2:expr) { $body:expr } { $else:expr }) => {{
+        if let None = $expr && let None = $expr2 {
+            $body
+        } else {
+            $else
+        }
+    }};
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
new file mode 100644
index 00000000000..23700f89f10
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
@@ -0,0 +1,65 @@
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:19:30
+   |
+LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                              ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:19:52
+   |
+LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                                                    ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:22:5
+   |
+LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:22:5
+   |
+LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:26:30
+   |
+LL |     macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                              ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:26:52
+   |
+LL |     macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                                                    ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
new file mode 100644
index 00000000000..3af844f4f96
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
@@ -0,0 +1,45 @@
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:19:30
+   |
+LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                              ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:19:52
+   |
+LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+   |                                                    ^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:22:5
+   |
+LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/edition-gate-macro-error.rs:22:5
+   |
+LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
new file mode 100644
index 00000000000..89b555d2c50
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
@@ -0,0 +1,30 @@
+//@ revisions: edition2021 edition2024
+//@ compile-flags: -Z lint-mir -Z validate-mir
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ aux-build:macro-in-2021.rs
+//@ aux-build:macro-in-2024.rs
+
+use std::unreachable as never;
+
+// Compiletest doesn't specify the needed --extern flags to make `extern crate` unneccessary
+extern crate macro_in_2021;
+extern crate macro_in_2024;
+
+fn main() {
+    // Gated on both 2021 and 2024 if the `if` comes from a 2021 macro
+    // Gated only on 2021 if the `if` comes from a 2024 macro
+    // No gating if both the `if` and the chain are from a 2024 macro
+
+    macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+    //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR `let` expressions in this position are unstable
+    macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+    //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR `let` expressions in this position are unstable
+
+    macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+    //[edition2021]~^ ERROR `let` expressions in this position are unstable
+    //[edition2021]~| ERROR `let` expressions in this position are unstable
+    macro_in_2024::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs
new file mode 100644
index 00000000000..5dd928dbce5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs
@@ -0,0 +1,76 @@
+//@ revisions: edition2021 edition2024
+//@ compile-flags: -Z lint-mir -Z validate-mir
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ aux-build:macro-in-2021.rs
+//@ aux-build:macro-in-2024.rs
+//@ run-pass
+
+#![allow(dead_code)]
+
+use std::unreachable as never;
+use std::cell::RefCell;
+use std::convert::TryInto;
+
+// Compiletest doesn't specify the needed --extern flags to make `extern crate` unneccessary
+extern crate macro_in_2021;
+extern crate macro_in_2024;
+
+#[derive(Default)]
+struct DropOrderCollector(RefCell<Vec<u32>>);
+
+struct LoudDrop<'a>(&'a DropOrderCollector, u32);
+
+impl Drop for LoudDrop<'_> {
+    fn drop(&mut self) {
+        println!("{}", self.1);
+        self.0.0.borrow_mut().push(self.1);
+    }
+}
+
+impl DropOrderCollector {
+    fn print(&self, n: u32) {
+        println!("{n}");
+        self.0.borrow_mut().push(n)
+    }
+    fn some_loud(&self, n: u32) -> Option<LoudDrop> {
+        Some(LoudDrop(self, n))
+    }
+
+    #[track_caller]
+    fn validate(self) {
+        assert!(
+            self.0
+                .into_inner()
+                .into_iter()
+                .enumerate()
+                .all(|(idx, item)| idx + 1 == item.try_into().unwrap())
+        );
+    }
+    fn with_macro_2021(self) {
+        // Edition 2021 drop behaviour
+        macro_in_2021::make_if!((let None = self.some_loud(2)) { never!() } {self.print(1) });
+        macro_in_2021::make_if!(let (self.some_loud(4)) { never!() } { self.print(3) });
+        self.validate();
+    }
+    fn with_macro_2024(self) {
+        // Edition 2024 drop behaviour
+        macro_in_2024::make_if!((let None = self.some_loud(1)) { never!() } { self.print(2) });
+        macro_in_2024::make_if!(let (self.some_loud(3)) { never!() } { self.print(4) });
+        self.validate();
+    }
+}
+
+fn main() {
+    // 2021 drop order if it's a 2021 macro creating the `if`
+    // 2024 drop order if it's a 2024 macro creating the `if`
+
+    // Compare this with edition-gate-macro-error.rs: We want to avoid exposing 2021 drop order,
+    // because it can create bad MIR (issue #104843)
+    // This test doesn't contain any let chains at all: it should be understood
+    // in combination with `edition-gate-macro-error.rs`
+
+    DropOrderCollector::default().with_macro_2021();
+    DropOrderCollector::default().with_macro_2024();
+
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
index 3c572054e3f..8e7db9a430c 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn main() {
     let opt = Some(1i32);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
index 59c81d053bc..0113a87cecc 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
@@ -1,6 +1,5 @@
 //@ check-pass
-
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn main() {
     let x = Some(vec!["test"]);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
index ea4b34eacba..f5d87d6999a 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
@@ -1,6 +1,5 @@
 //@ check-pass
-
-#![feature(let_chains)]
+//@ edition:2024
 
 fn main() {
     let opt = Some("foo bar");
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
index f90b9ab0d40..f6de37867d8 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
@@ -2,7 +2,6 @@ fn main() {
     match true {
         _ if let true = true && true => {}
         //~^ ERROR `if let` guards are
-        //~| ERROR `let` expressions in this
         _ => {}
     }
 }
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
index 637ae4915ed..17fa37d2df3 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
@@ -9,16 +9,6 @@ LL |         _ if let true = true && true => {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/issue-93150.rs:3:14
-   |
-LL |         _ if let true = true && 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
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
index 77756d0bee0..7589b33a73c 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
@@ -1,6 +1,7 @@
 //@ compile-flags: -Zvalidate-mir -C opt-level=3
 //@ build-pass
-#![feature(let_chains)]
+//@ edition: 2024
+
 struct TupleIter<T, I: Iterator<Item = T>> {
     inner: I,
 }
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
index 2c7fe2eea33..7d8dfe37135 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
@@ -3,7 +3,6 @@
 //@ edition: 2024
 //@ check-pass
 
-#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 struct Pd;
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 4d1f12e3490..0fb5a26c5aa 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -12,7 +12,6 @@
 #![feature(dyn_star)]
 #![feature(explicit_tail_calls)]
 #![feature(gen_blocks)]
-#![feature(let_chains)]
 #![feature(more_qualified_paths)]
 #![feature(never_patterns)]
 #![feature(never_type)]
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index d8da941a340..8febd2d6d49 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -13,7 +13,6 @@
 #![feature(dyn_star)]
 #![feature(explicit_tail_calls)]
 #![feature(gen_blocks)]
-#![feature(let_chains)]
 #![feature(more_qualified_paths)]
 #![feature(never_patterns)]
 #![feature(never_type)]
diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs
index 0c447ae669d..95280f97dac 100644
--- a/tests/ui/unpretty/expanded-interpolation.rs
+++ b/tests/ui/unpretty/expanded-interpolation.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zunpretty=expanded
+//@ edition:2024
 //@ check-pass
-//@ edition: 2015
 
 // This test covers the AST pretty-printer's insertion of parentheses in some
 // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
@@ -8,7 +8,6 @@
 // Rust syntax. We also test negative cases: the pretty-printer should not be
 // synthesizing parentheses indiscriminately; only where necessary.
 
-#![feature(let_chains)]
 #![feature(if_let_guard)]
 
 macro_rules! expr {
diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout
index 10729a96ef5..d46b46b67f4 100644
--- a/tests/ui/unpretty/expanded-interpolation.stdout
+++ b/tests/ui/unpretty/expanded-interpolation.stdout
@@ -1,8 +1,7 @@
 #![feature(prelude_import)]
-#![no_std]
 //@ compile-flags: -Zunpretty=expanded
+//@ edition:2024
 //@ check-pass
-//@ edition: 2015
 
 // This test covers the AST pretty-printer's insertion of parentheses in some
 // macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
@@ -10,10 +9,9 @@
 // Rust syntax. We also test negative cases: the pretty-printer should not be
 // synthesizing parentheses indiscriminately; only where necessary.
 
-#![feature(let_chains)]
 #![feature(if_let_guard)]
 #[prelude_import]
-use ::std::prelude::rust_2015::*;
+use std::prelude::rust_2024::*;
 #[macro_use]
 extern crate std;