diff options
| author | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2024-05-24 09:32:20 +0000 |
|---|---|---|
| committer | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2024-05-28 11:36:30 +0000 |
| commit | 53e3c3271f313df7e137589f3984772b0db4f031 (patch) | |
| tree | 5e700385a46229a8b68d7c832c7664a8749f7f81 | |
| parent | be94ca0bcdff9b55a4f15f66f6538e6b3e1b6793 (diff) | |
Make body-visiting logic reusable
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/region.rs | 112 |
1 files changed, 59 insertions, 53 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index e51f95eed02..687f0f09a0b 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -782,25 +782,8 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } self.enter_scope(Scope { id, data: ScopeData::Node }); } -} - -impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { - fn visit_block(&mut self, b: &'tcx Block<'tcx>) { - resolve_block(self, b); - } - - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { - let body_id = body.id(); - let owner_id = self.tcx.hir().body_owner_def_id(body_id); - - debug!( - "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", - owner_id, - self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span), - body_id, - self.cx.parent - ); + fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) { // Save all state that is specific to the outer function // body. These will be restored once down below, once we've // visited the body. @@ -812,43 +795,12 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // control flow assumptions. This doesn't apply to nested // bodies within the `+=` statements. See #69307. let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); - self.terminating_scopes.insert(body.value.hir_id.local_id); - - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite }); - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments }); + self.terminating_scopes.insert(hir_id.local_id); - // The arguments and `self` are parented to the fn. - self.cx.var_parent = self.cx.parent.take(); - for param in body.params { - self.visit_pat(param.pat); - } + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite }); + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments }); - // The body of the every fn is a root scope. - self.cx.parent = self.cx.var_parent; - if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { - self.visit_expr(body.value) - } else { - // Only functions have an outer terminating (drop) scope, while - // temporaries in constant initializers may be 'static, but only - // according to rvalue lifetime semantics, using the same - // syntactical rules used for let initializers. - // - // e.g., in `let x = &f();`, the temporary holding the result from - // the `f()` call lives for the entirety of the surrounding block. - // - // Similarly, `const X: ... = &f();` would have the result of `f()` - // live for `'static`, implying (if Drop restrictions on constants - // ever get lifted) that the value *could* have a destructor, but - // it'd get leaked instead of the destructor running during the - // evaluation of `X` (if at all allowed by CTFE). - // - // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, - // would *not* let the `f()` temporary escape into an outer scope - // (i.e., `'static`), which means that after `g` returns, it drops, - // and all the associated destruction scope rules apply. - self.cx.var_parent = None; - resolve_local(self, None, Some(body.value)); - } + f(self); // Restore context we had at the start. self.expr_and_pat_count = outer_ec; @@ -856,6 +808,60 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { self.terminating_scopes = outer_ts; self.pessimistic_yield = outer_pessimistic_yield; } +} + +impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { + fn visit_block(&mut self, b: &'tcx Block<'tcx>) { + resolve_block(self, b); + } + + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + let body_id = body.id(); + let owner_id = self.tcx.hir().body_owner_def_id(body_id); + + debug!( + "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", + owner_id, + self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span), + body_id, + self.cx.parent + ); + + self.enter_body(body.value.hir_id, |this| { + if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { + // The arguments and `self` are parented to the fn. + this.cx.var_parent = this.cx.parent.take(); + for param in body.params { + this.visit_pat(param.pat); + } + + // The body of the every fn is a root scope. + this.cx.parent = this.cx.var_parent; + this.visit_expr(body.value) + } else { + // Only functions have an outer terminating (drop) scope, while + // temporaries in constant initializers may be 'static, but only + // according to rvalue lifetime semantics, using the same + // syntactical rules used for let initializers. + // + // e.g., in `let x = &f();`, the temporary holding the result from + // the `f()` call lives for the entirety of the surrounding block. + // + // Similarly, `const X: ... = &f();` would have the result of `f()` + // live for `'static`, implying (if Drop restrictions on constants + // ever get lifted) that the value *could* have a destructor, but + // it'd get leaked instead of the destructor running during the + // evaluation of `X` (if at all allowed by CTFE). + // + // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, + // would *not* let the `f()` temporary escape into an outer scope + // (i.e., `'static`), which means that after `g` returns, it drops, + // and all the associated destruction scope rules apply. + this.cx.var_parent = None; + resolve_local(this, None, Some(body.value)); + } + }) + } fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) { resolve_arm(self, a); |
