From 4ec688110f21b04ab243c5a3e56997ea6c33dbcc Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 3 Jul 2025 03:31:55 -0700 Subject: [PATCH 1/3] add more tests for `if let` guard drop order --- tests/ui/drop/if-let-guards.rs | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/ui/drop/if-let-guards.rs diff --git a/tests/ui/drop/if-let-guards.rs b/tests/ui/drop/if-let-guards.rs new file mode 100644 index 0000000000000..918245e029ca6 --- /dev/null +++ b/tests/ui/drop/if-let-guards.rs @@ -0,0 +1,89 @@ +//! Tests drop order for `if let` guard bindings and temporaries. This is for behavior specific to +//! `match` expressions, whereas `tests/ui/drop/drop-order-comparisons.rs` compares `let` chains in +//! guards to `let` chains in `if` expressions. Drop order for `let` chains in guards shouldn't +//! differ between Editions, so we test on both 2021 and 2024, expecting the same results. +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 +//@ run-pass + +#![feature(if_let_guard)] +#![deny(rust_2024_compatibility)] + +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)] { + // 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)] + && true => { let _a = o.log(1); } + _ => unreachable!(), + } + }); + + // Sanity check: we don't move out of the match scrutinee when the guard fails. + assert_drop_order(1..=4, |o| { + // The scrutinee uses the drop order for arrays since its elements aren't moved. + match [o.log(3), o.log(4)] { + [_x, _y] if let _z = o.log(1) + && false => unreachable!(), + _ => { let _a = o.log(2); } + } + }); + + // Test `let` guards' temporaries are dropped immediately when a guard fails, even if the guard + // is lowered and run multiple times on the same arm due to or-patterns. + assert_drop_order(1..=8, |o| { + let mut _x = 1; + // The match's scrutinee isn't bound by-move, so it outlives the match. + match o.log(8) { + // Failing a guard breaks out of the arm's scope, dropping the `let` guard's scrutinee. + _ | _ | _ if let _ = o.log(_x) + && { _x += 1; false } => unreachable!(), + // The temporaries from a failed guard are dropped before testing the next guard. + _ if let _ = o.log(5) + && { o.push(4); false } => unreachable!(), + // If the guard succeeds, we stay in the arm's scope to execute its body. + _ if let _ = o.log(7) + && true => { o.log(6); } + _ => unreachable!(), + } + }); +} + +// # Test scaffolding... + +struct DropOrder(RefCell>); +struct LogDrop<'o>(&'o DropOrder, u64); + +impl DropOrder { + fn log(&self, n: u64) -> LogDrop<'_> { + LogDrop(self, n) + } + fn push(&self, n: u64) { + self.0.borrow_mut().push(n); + } +} + +impl<'o> Drop for LogDrop<'o> { + fn drop(&mut self) { + self.0.push(self.1); + } +} + +#[track_caller] +fn assert_drop_order( + ex: impl IntoIterator, + f: impl Fn(&DropOrder), +) { + let order = DropOrder(RefCell::new(Vec::new())); + f(&order); + let order = order.0.into_inner(); + let expected: Vec = ex.into_iter().collect(); + assert_eq!(order, expected); +} From b2241c78c86a15b8e7e842f036135df4478de0fe Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 3 Jul 2025 06:10:37 -0700 Subject: [PATCH 2/3] add a scope for `if let` guard temporaries and bindings This ensures `if let` guard temporaries and bindings are dropped before the match arm's pattern's bindings. --- .../rustc_hir_analysis/src/check/region.rs | 5 ++ compiler/rustc_middle/src/middle/region.rs | 6 ++ compiler/rustc_middle/src/ty/rvalue_scopes.rs | 2 +- .../src/builder/matches/mod.rs | 78 ++++++++++--------- compiler/rustc_mir_build/src/builder/scope.rs | 23 ++++-- tests/ui/drop/if-let-guards.rs | 5 +- .../ui/thir-print/thir-tree-loop-match.stdout | 16 ++-- tests/ui/thir-print/thir-tree-match.stdout | 12 +-- 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 95f6fba6487a6..d43ac0537582f 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 800c1af660a4a..857d041224fa9 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 9bf6e3a759004..7dfe2d280514f 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 aebd78515a25d..c9a561fc54a2c 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 1240b34cf9d43..403e7167a69c6 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 918245e029ca6..bd353112c09bc 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 5c4c50cb15623..86d37e987e2cb 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 2049c531abd99..31b9b3b999551 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) From 0bdaef5b63fe2d557483e72732e463b86ffb041b Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 7 Aug 2025 16:17:54 -0700 Subject: [PATCH 3/3] only introduce a guard scope for arms with guards --- compiler/rustc_hir_analysis/src/check/region.rs | 10 +++++----- .../rustc_mir_build/src/builder/matches/mod.rs | 10 ++++++---- compiler/rustc_mir_build/src/builder/scope.rs | 14 ++++++++++++++ tests/ui/thir-print/thir-tree-loop-match.stdout | 16 ++++++++-------- tests/ui/thir-print/thir-tree-match.stdout | 12 ++++++------ 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index d43ac0537582f..f5770b7312ddf 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -198,12 +198,12 @@ 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 { + // 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; resolve_cond(visitor, guard); } resolve_expr(visitor, arm.body, false); diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index c9a561fc54a2c..d5822a65b1784 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -434,12 +434,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); let match_scope = self.local_scope(); + let guard_scope = arm + .guard + .map(|_| region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope }); self.in_scope(arm_scope, arm.lint_level, |this| { - let guard_scope = - region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope }; - this.in_scope((guard_scope, arm_source_info), LintLevel::Inherited, |this| { + this.opt_in_scope(guard_scope.map(|scope| (scope, arm_source_info)), |this| { + // `if let` guard temps needing deduplicating will be in the guard scope. let old_dedup_scope = - mem::replace(&mut this.fixed_temps_scope, Some(guard_scope)); + mem::replace(&mut this.fixed_temps_scope, 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 diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 403e7167a69c6..9665987362202 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -697,6 +697,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(rv) } + /// Convenience wrapper that executes `f` either within the current scope or a new scope. + /// Used for pattern matching, which introduces an additional scope for patterns with guards. + pub(crate) fn opt_in_scope( + &mut self, + opt_region_scope: Option<(region::Scope, SourceInfo)>, + f: impl FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd, + ) -> BlockAnd { + if let Some(region_scope) = opt_region_scope { + self.in_scope(region_scope, LintLevel::Inherited, f) + } else { + f(self) + } + } + /// Push a scope onto the stack. You can then build code in this /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 86d37e987e2cb..5c4c50cb15623 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(MatchGuard(16)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(16)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(16)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(24)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(24)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(24)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(24)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(24)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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 31b9b3b999551..2049c531abd99 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(MatchGuard(14)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(14)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(20)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(20)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(26)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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(MatchGuard(26)), backwards_incompatible: None } + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(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)