diff options
| author | Matthew Jasper <mjjasper1@gmail.com> | 2024-01-03 16:32:13 +0000 |
|---|---|---|
| committer | Matthew Jasper <mjjasper1@gmail.com> | 2024-01-05 10:56:59 +0000 |
| commit | 1a267e3f40c4c6e32482a7dd98c512f4664a329e (patch) | |
| tree | a435dca89a742799998ceb8661bbead879bcdbc2 | |
| parent | a549711f6e3dc804783652810a40653719dd0af7 (diff) | |
| download | rust-1a267e3f40c4c6e32482a7dd98c512f4664a329e.tar.gz rust-1a267e3f40c4c6e32482a7dd98c512f4664a329e.zip | |
Restore if let guard temporary scoping difference
Match guards with an if let guard or an if let chain guard should have a temporary scope of the whole arm. This is to allow ref bindings to temporaries to borrow check.
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/region.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/mod.rs | 6 | ||||
| -rw-r--r-- | tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs | 72 |
3 files changed, 89 insertions, 2 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index c3bdf94d30f..542e69a6c34 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -177,6 +177,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { + fn has_let_expr(expr: &Expr<'_>) -> bool { + match &expr.kind { + hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + hir::ExprKind::Let(..) => true, + _ => false, + } + } + let prev_cx = visitor.cx; visitor.terminating_scopes.insert(arm.hir_id.local_id); @@ -184,8 +192,9 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); visitor.cx.var_parent = visitor.cx.parent; - if let Some(expr) = arm.guard { - // Check for if?? + if let Some(expr) = arm.guard + && !has_let_expr(expr) + { visitor.terminating_scopes.insert(expr.hir_id.local_id); } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 483e70fd6f1..906b3205ca7 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -33,6 +33,12 @@ use std::borrow::Borrow; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Lowers a condition in a way that ensures that variables bound in any let + /// expressions are definitely initialized in the if body. + /// + /// If `declare_bindings` is false then variables created in `let` + /// expressions will not be declared. This is for if let guards on arms with + /// an or pattern, where the guard is lowered multiple times. pub(crate) fn then_else_break( &mut self, mut block: BasicBlock, diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs new file mode 100644 index 00000000000..9e6e23e8882 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs @@ -0,0 +1,72 @@ +// Ensure that temporaries in if-let guards live for the arm +// regression test for #118593 + +// check-pass + +#![feature(if_let_guard)] +#![feature(let_chains)] + +fn get_temp() -> Option<String> { + None +} + +fn let_guard(num: u8) { + match num { + 1 | 2 if let Some(ref a) = get_temp() => { + let _b = a; + } + _ => {} + } + match num { + 3 | 4 if let Some(ref mut c) = get_temp() => { + let _d = c; + } + _ => {} + } +} + +fn let_let_chain_guard(num: u8) { + match num { + 5 | 6 + if let Some(ref a) = get_temp() + && let Some(ref b) = get_temp() => + { + let _x = a; + let _y = b; + } + _ => {} + } + match num { + 7 | 8 + if let Some(ref mut c) = get_temp() + && let Some(ref mut d) = get_temp() => + { + let _w = c; + let _z = d; + } + _ => {} + } +} + +fn let_cond_chain_guard(num: u8) { + match num { + 9 | 10 + if let Some(ref a) = get_temp() + && true => + { + let _x = a; + } + _ => {} + } + match num { + 11 | 12 + if let Some(ref mut b) = get_temp() + && true => + { + let _w = b; + } + _ => {} + } +} + +fn main() {} |
