about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs5
-rw-r--r--compiler/rustc_middle/src/middle/region.rs6
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs78
-rw-r--r--compiler/rustc_mir_build/src/builder/scope.rs23
-rw-r--r--tests/ui/drop/if-let-guards.rs5
-rw-r--r--tests/ui/thir-print/thir-tree-loop-match.stdout16
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout12
8 files changed, 84 insertions, 63 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 95f6fba6487..d43ac053758 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -198,6 +198,11 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir:
     visitor.cx.var_parent = visitor.cx.parent;
 
     resolve_pat(visitor, arm.pat);
+    // We introduce a new scope to contain bindings and temporaries from `if let` guards, to
+    // ensure they're dropped before the arm's pattern's bindings. This extends to the end of
+    // the arm body and is the scope of its locals as well.
+    visitor.enter_scope(Scope { local_id: arm.hir_id.local_id, data: ScopeData::MatchGuard });
+    visitor.cx.var_parent = visitor.cx.parent;
     if let Some(guard) = arm.guard {
         resolve_cond(visitor, guard);
     }
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 800c1af660a..857d041224f 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -96,6 +96,7 @@ impl fmt::Debug for Scope {
             ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.local_id),
             ScopeData::IfThen => write!(fmt, "IfThen({:?})", self.local_id),
             ScopeData::IfThenRescope => write!(fmt, "IfThen[edition2024]({:?})", self.local_id),
+            ScopeData::MatchGuard => write!(fmt, "MatchGuard({:?})", self.local_id),
             ScopeData::Remainder(fsi) => write!(
                 fmt,
                 "Remainder {{ block: {:?}, first_statement_index: {}}}",
@@ -131,6 +132,11 @@ pub enum ScopeData {
     /// whose lifetimes do not cross beyond this scope.
     IfThenRescope,
 
+    /// Scope of the condition and body of a match arm with a guard
+    /// Used for variables introduced in an if-let guard,
+    /// whose lifetimes do not cross beyond this scope.
+    MatchGuard,
+
     /// Scope following a `let id = expr;` binding in a block.
     Remainder(FirstStatementIndex),
 }
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index 9bf6e3a7590..7dfe2d28051 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -44,7 +44,7 @@ impl RvalueScopes {
                     debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
                     return (Some(id), backwards_incompatible);
                 }
-                ScopeData::IfThenRescope => {
+                ScopeData::IfThenRescope | ScopeData::MatchGuard => {
                     debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]");
                     return (Some(p), backwards_incompatible);
                 }
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index aebd78515a2..c9a561fc54a 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -435,46 +435,50 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let arm_scope = (arm.scope, arm_source_info);
                 let match_scope = self.local_scope();
                 self.in_scope(arm_scope, arm.lint_level, |this| {
-                    let old_dedup_scope =
-                        mem::replace(&mut this.fixed_temps_scope, Some(arm.scope));
-
-                    // `try_to_place` may fail if it is unable to resolve the given
-                    // `PlaceBuilder` inside a closure. In this case, we don't want to include
-                    // a scrutinee place. `scrutinee_place_builder` will fail to be resolved
-                    // if the only match arm is a wildcard (`_`).
-                    // Example:
-                    // ```
-                    // let foo = (0, 1);
-                    // let c = || {
-                    //    match foo { _ => () };
-                    // };
-                    // ```
-                    let scrutinee_place = scrutinee_place_builder.try_to_place(this);
-                    let opt_scrutinee_place =
-                        scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span));
-                    let scope = this.declare_bindings(
-                        None,
-                        arm.span,
-                        &arm.pattern,
-                        arm.guard,
-                        opt_scrutinee_place,
-                    );
+                    let guard_scope =
+                        region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope };
+                    this.in_scope((guard_scope, arm_source_info), LintLevel::Inherited, |this| {
+                        let old_dedup_scope =
+                            mem::replace(&mut this.fixed_temps_scope, Some(guard_scope));
+
+                        // `try_to_place` may fail if it is unable to resolve the given
+                        // `PlaceBuilder` inside a closure. In this case, we don't want to include
+                        // a scrutinee place. `scrutinee_place_builder` will fail to be resolved
+                        // if the only match arm is a wildcard (`_`).
+                        // Example:
+                        // ```
+                        // let foo = (0, 1);
+                        // let c = || {
+                        //    match foo { _ => () };
+                        // };
+                        // ```
+                        let scrutinee_place = scrutinee_place_builder.try_to_place(this);
+                        let opt_scrutinee_place =
+                            scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span));
+                        let scope = this.declare_bindings(
+                            None,
+                            arm.span,
+                            &arm.pattern,
+                            arm.guard,
+                            opt_scrutinee_place,
+                        );
 
-                    let arm_block = this.bind_pattern(
-                        outer_source_info,
-                        branch,
-                        &built_match_tree.fake_borrow_temps,
-                        scrutinee_span,
-                        Some((arm, match_scope)),
-                    );
+                        let arm_block = this.bind_pattern(
+                            outer_source_info,
+                            branch,
+                            &built_match_tree.fake_borrow_temps,
+                            scrutinee_span,
+                            Some((arm, match_scope)),
+                        );
 
-                    this.fixed_temps_scope = old_dedup_scope;
+                        this.fixed_temps_scope = old_dedup_scope;
 
-                    if let Some(source_scope) = scope {
-                        this.source_scope = source_scope;
-                    }
+                        if let Some(source_scope) = scope {
+                            this.source_scope = source_scope;
+                        }
 
-                    this.expr_into_dest(destination, arm_block, arm.body)
+                        this.expr_into_dest(destination, arm_block, arm.body)
+                    })
                 })
                 .into_block()
             })
@@ -2523,7 +2527,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // bindings and temporaries created for and by the guard. As a result, the drop order
             // for the arm will correspond to the binding order of the final sub-branch lowered.
             if matches!(schedule_drops, ScheduleDrops::No) {
-                self.clear_top_scope(arm.scope);
+                self.clear_match_arm_and_guard_scopes(arm.scope);
             }
 
             let source_info = self.source_info(guard_span);
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index 1240b34cf9d..403e7167a69 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -1750,17 +1750,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         success_block
     }
 
-    /// Unschedules any drops in the top scope.
+    /// Unschedules any drops in the top two scopes.
     ///
-    /// This is only needed for `match` arm scopes, because they have one
-    /// entrance per pattern, but only one exit.
-    pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
-        let top_scope = self.scopes.scopes.last_mut().unwrap();
+    /// This is only needed for pattern-matches combining guards and or-patterns: or-patterns lead
+    /// to guards being lowered multiple times before lowering the arm body, so we unschedle drops
+    /// for guards' temporaries and bindings between lowering each instance of an match arm's guard.
+    pub(crate) fn clear_match_arm_and_guard_scopes(&mut self, region_scope: region::Scope) {
+        let [.., arm_scope, guard_scope] = &mut *self.scopes.scopes else {
+            bug!("matches with guards should introduce separate scopes for the pattern and guard");
+        };
 
-        assert_eq!(top_scope.region_scope, region_scope);
+        assert_eq!(arm_scope.region_scope, region_scope);
+        assert_eq!(guard_scope.region_scope.data, region::ScopeData::MatchGuard);
+        assert_eq!(guard_scope.region_scope.local_id, region_scope.local_id);
 
-        top_scope.drops.clear();
-        top_scope.invalidate_cache();
+        arm_scope.drops.clear();
+        arm_scope.invalidate_cache();
+        guard_scope.drops.clear();
+        guard_scope.invalidate_cache();
     }
 }
 
diff --git a/tests/ui/drop/if-let-guards.rs b/tests/ui/drop/if-let-guards.rs
index 918245e029c..bd353112c09 100644
--- a/tests/ui/drop/if-let-guards.rs
+++ b/tests/ui/drop/if-let-guards.rs
@@ -14,13 +14,12 @@ use core::{cell::RefCell, ops::Drop};
 
 fn main() {
     // Test that `let` guard bindings and temps are dropped before the arm's pattern's bindings.
-    // TODO: this is currently the old behavior (`let` bindings dropped after arm bindings).
     assert_drop_order(1..=6, |o| {
         // We move out of the scrutinee, so the drop order of the array's elements are based on
         // binding declaration order, and they're dropped in the arm's scope.
-        match [o.log(3), o.log(2)] {
+        match [o.log(6), o.log(5)] {
             // Partially move from the guard temporary to test drops both for temps and the binding.
-            [_x, _y] if let [_, _z, _] = [o.log(6), o.log(4), o.log(5)]
+            [_x, _y] if let [_, _z, _] = [o.log(4), o.log(2), o.log(3)]
                 && true => { let _a = o.log(1); }
             _ => unreachable!(),
         }
diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout
index 5c4c50cb156..86d37e987e2 100644
--- a/tests/ui/thir-print/thir-tree-loop-match.stdout
+++ b/tests/ui/thir-print/thir-tree-loop-match.stdout
@@ -129,7 +129,7 @@ body:
                                                                                                 body: 
                                                                                                     Expr {
                                                                                                         ty: bool
-                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
+                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(16)), backwards_incompatible: None }
                                                                                                         span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
                                                                                                         kind: 
                                                                                                             Scope {
@@ -138,14 +138,14 @@ body:
                                                                                                                 value:
                                                                                                                     Expr {
                                                                                                                         ty: bool
-                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
+                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(16)), backwards_incompatible: None }
                                                                                                                         span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
                                                                                                                         kind: 
                                                                                                                             NeverToAny {
                                                                                                                                 source:
                                                                                                                                     Expr {
                                                                                                                                         ty: !
-                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
+                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(16)), backwards_incompatible: None }
                                                                                                                                         span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
                                                                                                                                         kind: 
                                                                                                                                             Block {
@@ -227,7 +227,7 @@ body:
                                                                                                 body: 
                                                                                                     Expr {
                                                                                                         ty: bool
-                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(24)), backwards_incompatible: None }
                                                                                                         span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
                                                                                                         kind: 
                                                                                                             Scope {
@@ -236,21 +236,21 @@ body:
                                                                                                                 value:
                                                                                                                     Expr {
                                                                                                                         ty: bool
-                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(24)), backwards_incompatible: None }
                                                                                                                         span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
                                                                                                                         kind: 
                                                                                                                             NeverToAny {
                                                                                                                                 source:
                                                                                                                                     Expr {
                                                                                                                                         ty: !
-                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(24)), backwards_incompatible: None }
                                                                                                                                         span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
                                                                                                                                         kind: 
                                                                                                                                             Return {
                                                                                                                                                 value:
                                                                                                                                                     Expr {
                                                                                                                                                         ty: bool
-                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(24)), backwards_incompatible: None }
                                                                                                                                                         span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
                                                                                                                                                         kind: 
                                                                                                                                                             Scope {
@@ -259,7 +259,7 @@ body:
                                                                                                                                                                 value:
                                                                                                                                                                     Expr {
                                                                                                                                                                         ty: bool
-                                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(24)), backwards_incompatible: None }
                                                                                                                                                                         span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
                                                                                                                                                                         kind: 
                                                                                                                                                                             VarRef {
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 2049c531abd..31b9b3b9995 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -123,7 +123,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(14)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -132,7 +132,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(14)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -175,7 +175,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(20)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -184,7 +184,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(20)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -219,7 +219,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(26)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -228,7 +228,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(MatchGuard(26)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)