about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDing Xiang Fei <dingxiangfei2009@protonmail.ch>2022-04-01 21:12:18 +0800
committerDing Xiang Fei <dingxiangfei2009@protonmail.ch>2022-05-22 16:46:50 +0800
commit6044fbe4625579dadb6ef58305f97f2fb414c8cc (patch)
treeb6b73468ce0c48fb982371e97a58b9de3c5ae739
parentbb5e6c984de2fbabba37655551f4bab16fbd9e5e (diff)
downloadrust-6044fbe4625579dadb6ef58305f97f2fb414c8cc.tar.gz
rust-6044fbe4625579dadb6ef58305f97f2fb414c8cc.zip
factor out the rvalue lifetime rule
remove region_scope_tree from RegionCtxt

Apply suggestions from code review

Co-authored-by: Niko Matsakis <niko@alum.mit.edu>
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/middle/region.rs78
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs16
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query.rs1
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs57
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs28
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs6
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs9
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs20
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs5
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs5
-rw-r--r--compiler/rustc_typeck/src/check/region.rs (renamed from compiler/rustc_passes/src/region.rs)90
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs5
-rw-r--r--compiler/rustc_typeck/src/check/rvalue_scopes.rs83
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs46
25 files changed, 363 insertions, 192 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1a0cac8fe79..cebf6876936 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1370,7 +1370,7 @@ pub enum UnsafeSource {
     UserProvided,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 pub struct BodyId {
     pub hir_id: HirId,
 }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index def061aaea0..2f0bb24537e 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -33,7 +33,6 @@ macro_rules! arena_types {
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
             // Required for the incremental on-disk cache
             [] mir_keys: rustc_hir::def_id::DefIdSet,
-            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
             [] dropck_outlives:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index af16e5e3fc8..30ef6b775f5 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -203,7 +203,7 @@ impl Scope {
 pub type ScopeDepth = u32;
 
 /// The region scope tree encodes information about region relationships.
-#[derive(Default, Debug)]
+#[derive(TyEncodable, TyDecodable, Default, Debug)]
 pub struct ScopeTree {
     /// If not empty, this body is the root of this region hierarchy.
     pub root_body: Option<hir::HirId>,
@@ -223,15 +223,12 @@ pub struct ScopeTree {
     /// Maps from a `NodeId` to the associated destruction scope (if any).
     destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
 
-    /// `rvalue_scopes` includes entries for those expressions whose
-    /// cleanup scope is larger than the default. The map goes from the
-    /// expression ID to the cleanup scope id. For rvalues not present in
-    /// this table, the appropriate cleanup scope is the innermost
-    /// enclosing statement, conditional expression, or repeating
-    /// block (see `terminating_scopes`).
-    /// In constants, None is used to indicate that certain expressions
-    /// escape into 'static and should have no local cleanup scope.
-    rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+    /// Identifies expressions which, if captured into a temporary, ought to
+    /// have a temporary whose lifetime extends to the end of the enclosing *block*,
+    /// and not the enclosing *statement*. Expressions that are not present in this
+    /// table are not rvalue candidates. The set of rvalue candidates is computed
+    /// during type check based on a traversal of the AST.
+    pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
 
     /// If there are any `yield` nested within a scope, this map
     /// stores the `Span` of the last one and its index in the
@@ -315,6 +312,17 @@ pub struct ScopeTree {
     pub body_expr_count: FxHashMap<hir::BodyId, usize>,
 }
 
+/// Identifies the reason that a given expression is an rvalue candidate
+/// (see the `rvalue_candidates` field for more information what rvalue
+/// candidates in general). In constants, the `lifetime` field is None
+/// to indicate that certain expressions escape into 'static and
+/// should have no local cleanup scope.
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum RvalueCandidateType {
+    Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
+    Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
+}
+
 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct YieldData {
     /// The `Span` of the yield.
@@ -349,12 +357,20 @@ impl ScopeTree {
         self.var_map.insert(var, lifetime);
     }
 
-    pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
-        debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        if let Some(lifetime) = lifetime {
-            assert!(var != lifetime.item_local_id());
+    pub fn record_rvalue_candidate(
+        &mut self,
+        var: hir::HirId,
+        candidate_type: RvalueCandidateType,
+    ) {
+        debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
+        match &candidate_type {
+            RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
+            | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
+                assert!(var.local_id != lifetime.item_local_id())
+            }
+            _ => {}
         }
-        self.rvalue_scopes.insert(var, lifetime);
+        self.rvalue_candidates.insert(var, candidate_type);
     }
 
     /// Returns the narrowest scope that encloses `id`, if any.
@@ -367,34 +383,6 @@ impl ScopeTree {
         self.var_map.get(&var_id).cloned()
     }
 
-    /// Returns the scope when the temp created by `expr_id` will be cleaned up.
-    pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
-        // Check for a designated rvalue scope.
-        if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
-            debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
-            return s;
-        }
-
-        // Otherwise, locate the innermost terminating scope
-        // if there's one. Static items, for instance, won't
-        // have an enclosing scope, hence no scope will be
-        // returned.
-        let mut id = Scope { id: expr_id, data: ScopeData::Node };
-
-        while let Some(&(p, _)) = self.parent_map.get(&id) {
-            match p.data {
-                ScopeData::Destruction => {
-                    debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id);
-                    return Some(id);
-                }
-                _ => id = p,
-            }
-        }
-
-        debug!("temporary_scope({:?}) = None", expr_id);
-        None
-    }
-
     /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
     /// `false` otherwise.
     ///
@@ -439,7 +427,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
             ref parent_map,
             ref var_map,
             ref destruction_scopes,
-            ref rvalue_scopes,
+            ref rvalue_candidates,
             ref yield_in_scope,
         } = *self;
 
@@ -448,7 +436,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
         parent_map.hash_stable(hcx, hasher);
         var_map.hash_stable(hcx, hasher);
         destruction_scopes.hash_stable(hcx, hasher);
-        rvalue_scopes.hash_stable(hcx, hasher);
+        rvalue_candidates.hash_stable(hcx, hasher);
         yield_in_scope.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 03084862e80..0c936b7ae10 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1048,12 +1048,6 @@ rustc_queries! {
         desc { "reachability" }
     }
 
-    /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
-    /// in the case of closures, this will be redirected to the enclosing function.
-    query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
-        desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
-    }
-
     /// Generates a MIR body for the shim.
     query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
         storage(ArenaCacheSelector<'tcx>)
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 31e131182cc..d9676dc412e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,6 +6,7 @@ use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::region::ScopeTree;
 use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
@@ -74,6 +75,8 @@ use std::mem;
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
+use super::RvalueScopes;
+
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -535,6 +538,17 @@ pub struct TypeckResults<'tcx> {
     /// issue by fake reading `t`.
     pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
 
+    /// Tracks critical information about regions in a body.
+    /// This includes containment relationship between regions,
+    /// liveness relationship between variables and regions and
+    /// information about yield points.
+    pub region_scope_tree: ScopeTree,
+
+    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+    /// by applying extended parameter rules.
+    /// Details may be find in `rustc_typeck::check::rvalue_scopes`.
+    pub rvalue_scopes: RvalueScopes,
+
     /// Stores the type, expression, span and optional scope span of all types
     /// that are live across the yield of this generator (if a generator).
     pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
@@ -572,6 +586,8 @@ impl<'tcx> TypeckResults<'tcx> {
             concrete_opaque_types: Default::default(),
             closure_min_captures: Default::default(),
             closure_fake_reads: Default::default(),
+            region_scope_tree: Default::default(),
+            rvalue_scopes: Default::default(),
             generator_interior_types: ty::Binder::dummy(Default::default()),
             treat_byte_string_as_slice: Default::default(),
             closure_size_eval: Default::default(),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8efa1621ade..775b06c6c38 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -72,6 +72,7 @@ pub use self::context::{
 };
 pub use self::instance::{Instance, InstanceDef};
 pub use self::list::List;
+pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
 pub use self::sty::RegionKind::*;
 pub use self::sty::TyKind::*;
@@ -118,6 +119,7 @@ mod generics;
 mod impls_ty;
 mod instance;
 mod list;
+mod rvalue_scopes;
 mod structural_impls;
 mod sty;
 
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 0398a83e220..65f41c5266d 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -6,7 +6,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
-use crate::middle::region;
 use crate::middle::resolve_lifetime::{
     LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
 };
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
new file mode 100644
index 00000000000..e86dafae338
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -0,0 +1,57 @@
+use crate::middle::region::{Scope, ScopeData, ScopeTree};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+
+/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
+/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
+pub struct RvalueScopes {
+    map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+}
+
+impl RvalueScopes {
+    pub fn new() -> Self {
+        Self { map: <_>::default() }
+    }
+
+    /// Returns the scope when the temp created by `expr_id` will be cleaned up.
+    pub fn temporary_scope(
+        &self,
+        region_scope_tree: &ScopeTree,
+        expr_id: hir::ItemLocalId,
+    ) -> Option<Scope> {
+        // Check for a designated rvalue scope.
+        if let Some(&s) = self.map.get(&expr_id) {
+            debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
+            return s;
+        }
+
+        // Otherwise, locate the innermost terminating scope
+        // if there's one. Static items, for instance, won't
+        // have an enclosing scope, hence no scope will be
+        // returned.
+        let mut id = Scope { id: expr_id, data: ScopeData::Node };
+
+        while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) {
+            match p.data {
+                ScopeData::Destruction => {
+                    debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
+                    return Some(id);
+                }
+                _ => id = p,
+            }
+        }
+
+        debug!("temporary_scope({expr_id:?}) = None");
+        None
+    }
+
+    /// Make an association between a sub-expression and an extended lifetime
+    pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
+        debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
+        if let Some(lifetime) = lifetime {
+            assert!(var != lifetime.item_local_id());
+        }
+        self.map.insert(var, lifetime);
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index a83328c0cab..e8b939fb51d 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -108,7 +108,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let_scope_stack.push(remainder_scope);
 
                     // Declare the bindings, which may create a source scope.
-                    let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
+                    let remainder_span =
+                        remainder_scope.span(this.tcx, &this.typeck_results.region_scope_tree);
 
                     let visibility_scope =
                         Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index fbe08dd6f0e..56acf65d9c5 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
         // Altough there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
+        if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) && schedule_drop{
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         }
         Place::from(local_id)
@@ -712,7 +712,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         for_guard: ForGuard,
     ) {
         let local_id = self.var_local_id(var, for_guard);
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
+        if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) {
             self.schedule_drop(span, region_scope, local_id, DropKind::Value);
         }
     }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 4ae74433df6..c42f2b3a67a 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -398,7 +398,6 @@ struct Builder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     infcx: &'a InferCtxt<'a, 'tcx>,
     typeck_results: &'tcx TypeckResults<'tcx>,
-    region_scope_tree: &'tcx region::ScopeTree,
     param_env: ty::ParamEnv<'tcx>,
 
     thir: &'a Thir<'tcx>,
@@ -881,7 +880,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             tcx,
             infcx,
             typeck_results: tcx.typeck_opt_const_arg(def),
-            region_scope_tree: tcx.region_scope_tree(def.did),
             param_env,
             def_id: def.did.to_def_id(),
             hir_id,
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 2d14a78accf..53f9706f021 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -916,7 +916,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             if scope.region_scope == region_scope {
-                let region_scope_span = region_scope.span(self.tcx, &self.region_scope_tree);
+                let region_scope_span =
+                    region_scope.span(self.tcx, &self.typeck_results.region_scope_tree);
                 // Attribute scope exit drops to scope's closing brace.
                 let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index b9879b9159f..480c5b195cc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -32,7 +32,8 @@ impl<'tcx> Cx<'tcx> {
     }
 
     pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id);
         let expr_scope =
             region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
 
@@ -161,7 +162,8 @@ impl<'tcx> Cx<'tcx> {
         let tcx = self.tcx;
         let expr_ty = self.typeck_results().expr_ty(expr);
         let expr_span = expr.span;
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
 
         let kind = match expr.kind {
             // Here comes the interesting stuff:
@@ -575,7 +577,9 @@ impl<'tcx> Cx<'tcx> {
             },
             hir::ExprKind::Loop(ref body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
-                let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
+                let temp_lifetime = self
+                    .rvalue_scopes
+                    .temporary_scope(self.region_scope_tree, body.hir_id.local_id);
                 let block = self.mirror_block(body);
                 let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
@@ -776,7 +780,8 @@ impl<'tcx> Cx<'tcx> {
         span: Span,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let (def_id, substs, user_ty) = match overloaded_callee {
             Some((def_id, substs)) => (def_id, substs, None),
             None => {
@@ -863,7 +868,9 @@ impl<'tcx> Cx<'tcx> {
             // a constant reference (or constant raw pointer for `static mut`) in MIR
             Res::Def(DefKind::Static(_), id) => {
                 let ty = self.tcx.static_ptr_ty(id);
-                let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+                let temp_lifetime = self
+                    .rvalue_scopes
+                    .temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
                 let kind = if self.tcx.is_thread_local_static(id) {
                     ExprKind::ThreadLocalRef(id)
                 } else {
@@ -939,7 +946,8 @@ impl<'tcx> Cx<'tcx> {
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let fun = self.method_callee(expr, span, overloaded_callee);
         let fun = self.thir.exprs.push(fun);
         let fun_ty = self.thir[fun].ty;
@@ -959,7 +967,9 @@ impl<'tcx> Cx<'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+        let temp_lifetime = self
+            .rvalue_scopes
+            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
         // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
@@ -1014,7 +1024,9 @@ impl<'tcx> Cx<'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
-        let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+        let temp_lifetime = self
+            .rvalue_scopes
+            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
 
         match upvar_capture {
             ty::UpvarCapture::ByValue => captured_place_expr,
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 81eb7efad37..13b4e90ca09 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -16,7 +16,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::mir::ConstantKind;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub(crate) fn thir_body<'tcx>(
@@ -51,6 +51,7 @@ struct Cx<'tcx> {
 
     pub(crate) region_scope_tree: &'tcx region::ScopeTree,
     pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>,
+    pub(crate) rvalue_scopes: &'tcx RvalueScopes,
 
     /// When applying adjustments to the expression
     /// with the given `HirId`, use the given `Span`,
@@ -71,8 +72,9 @@ impl<'tcx> Cx<'tcx> {
             tcx,
             thir: Thir::new(),
             param_env: tcx.param_env(def.did),
-            region_scope_tree: tcx.region_scope_tree(def.did),
+            region_scope_tree: &typeck_results.region_scope_tree,
             typeck_results,
+            rvalue_scopes: &typeck_results.rvalue_scopes,
             body_owner: def.did.to_def_id(),
             adjustment_span: None,
         }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 2c79ac49b36..510280ee386 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -38,7 +38,6 @@ mod liveness;
 pub mod loops;
 mod naked_functions;
 mod reachable;
-mod region;
 pub mod stability;
 mod upvars;
 mod weak_lang_items;
@@ -57,7 +56,6 @@ pub fn provide(providers: &mut Providers) {
     liveness::provide(providers);
     intrinsicck::provide(providers);
     reachable::provide(providers);
-    region::provide(providers);
     stability::provide(providers);
     upvars::provide(providers);
 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 3249157c4f4..649bc211321 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -4,6 +4,7 @@ use crate::astconv::{
 };
 use crate::check::callee::{self, DeferredCallResolution};
 use crate::check::method::{self, MethodCallee, SelfSource};
+use crate::check::{region, rvalue_scopes};
 use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 
 use rustc_data_structures::captures::Captures;
@@ -620,6 +621,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
     }
 
+    pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
+        let scope_tree = region::region_scope_tree(self.tcx, def_id);
+        let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, &scope_tree, def_id) };
+        let mut typeck_results = self.inh.typeck_results.borrow_mut();
+        typeck_results.region_scope_tree = scope_tree;
+        typeck_results.rvalue_scopes = rvalue_scopes;
+    }
+
     pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 60d19405bcf..02167ddef44 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use tracing::debug;
@@ -23,8 +23,9 @@ mod drop_ranges;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
+    region_scope_tree: &'a region::ScopeTree,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
-    region_scope_tree: &'tcx region::ScopeTree,
+    rvalue_scopes: &'a RvalueScopes,
     expr_count: usize,
     kind: hir::GeneratorKind,
     prev_unresolved_span: Option<Span>,
@@ -179,10 +180,12 @@ pub fn resolve_interior<'a, 'tcx>(
     kind: hir::GeneratorKind,
 ) {
     let body = fcx.tcx.hir().body(body_id);
+    let typeck_results = fcx.inh.typeck_results.borrow();
     let mut visitor = InteriorVisitor {
         fcx,
         types: FxIndexSet::default(),
-        region_scope_tree: fcx.tcx.region_scope_tree(def_id),
+        region_scope_tree: &typeck_results.region_scope_tree,
+        rvalue_scopes: &typeck_results.rvalue_scopes,
         expr_count: 0,
         kind,
         prev_unresolved_span: None,
@@ -192,7 +195,7 @@ pub fn resolve_interior<'a, 'tcx>(
     intravisit::walk_body(&mut visitor, body);
 
     // Check that we visited the same amount of expressions as the RegionResolutionVisitor
-    let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
+    let region_expr_count = typeck_results.region_scope_tree.body_expr_count(body_id).unwrap();
     assert_eq!(region_expr_count, visitor.expr_count);
 
     // The types are already kept in insertion order.
@@ -248,8 +251,9 @@ pub fn resolve_interior<'a, 'tcx>(
     let witness =
         fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
 
+    drop(typeck_results);
     // Store the generator types and spans into the typeck results for this generator.
-    visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types =
+    fcx.inh.typeck_results.borrow_mut().generator_interior_types =
         ty::Binder::bind_with_vars(type_causes, bound_vars);
 
     debug!(
@@ -381,12 +385,14 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // temporary on the stack that is live for the current temporary scope and then return a
         // reference to it. That value may be live across the entire temporary scope.
         let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
-            self.region_scope_tree.temporary_scope(expr.hir_id.local_id)
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
             debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
             match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
                 Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
-                None => self.region_scope_tree.temporary_scope(expr.hir_id.local_id),
+                None => {
+                    self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
+                }
             }
         };
 
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
index 800232d9549..ba6fcb98924 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -41,11 +41,12 @@ pub fn compute_drop_ranges<'a, 'tcx>(
     if fcx.sess().opts.debugging_opts.drop_tracking {
         let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
 
-        let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
+        let typeck_results = &fcx.typeck_results.borrow();
+        let num_exprs = typeck_results.region_scope_tree.body_expr_count(body.id()).unwrap_or(0);
         let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
             fcx.tcx.hir(),
             fcx.tcx,
-            &fcx.typeck_results.borrow(),
+            typeck_results,
             consumed_borrowed_places,
             body,
             num_exprs,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index cc62144e2b1..280fae5fe6d 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -85,7 +85,9 @@ pub mod method;
 mod op;
 mod pat;
 mod place_op;
+mod region;
 mod regionck;
+pub mod rvalue_scopes;
 mod upvar;
 mod wfcheck;
 pub mod writeback;
@@ -473,6 +475,9 @@ fn typeck_with_fallback<'tcx>(
         // because they don't constrain other type variables.
         fcx.closure_analyze(body);
         assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+        // Before the generator analysis, temporary scopes shall be marked to provide more
+        // precise information on types to be captured.
+        fcx.resolve_rvalue_scopes(def_id.to_def_id());
         fcx.resolve_generator_interiors(def_id.to_def_id());
 
         for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_typeck/src/check/region.rs
index d694782f9e7..43d189abcf7 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -14,7 +14,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
 use rustc_index::vec::Idx;
 use rustc_middle::middle::region::*;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::source_map;
 use rustc_span::Span;
@@ -527,7 +526,13 @@ fn resolve_local<'tcx>(
 
         if let Some(pat) = pat {
             if is_binding_pat(pat) {
-                record_rvalue_scope(visitor, &expr, blk_scope);
+                visitor.scope_tree.record_rvalue_candidate(
+                    expr.hir_id,
+                    RvalueCandidateType::Pattern {
+                        target: expr.hir_id.local_id,
+                        lifetime: blk_scope,
+                    },
+                );
             }
         }
     }
@@ -625,9 +630,15 @@ fn resolve_local<'tcx>(
         blk_id: Option<Scope>,
     ) {
         match expr.kind {
-            hir::ExprKind::AddrOf(_, _, ref subexpr) => {
-                record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
-                record_rvalue_scope(visitor, &subexpr, blk_id);
+            hir::ExprKind::AddrOf(_, _, subexpr) => {
+                record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
+                visitor.scope_tree.record_rvalue_candidate(
+                    subexpr.hir_id,
+                    RvalueCandidateType::Borrow {
+                        target: subexpr.hir_id.local_id,
+                        lifetime: blk_id,
+                    },
+                );
             }
             hir::ExprKind::Struct(_, fields, _) => {
                 for field in fields {
@@ -647,52 +658,15 @@ fn resolve_local<'tcx>(
                     record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
                 }
             }
-            _ => {}
-        }
-    }
-
-    /// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
-    /// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
-    /// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
-    /// statement.
-    ///
-    /// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
-    /// `<rvalue>` as `blk_id`:
-    ///
-    /// ```text
-    ///     ET = *ET
-    ///        | ET[...]
-    ///        | ET.f
-    ///        | (ET)
-    ///        | <rvalue>
-    /// ```
-    ///
-    /// Note: ET is intended to match "rvalues or places based on rvalues".
-    fn record_rvalue_scope<'tcx>(
-        visitor: &mut RegionResolutionVisitor<'tcx>,
-        expr: &hir::Expr<'_>,
-        blk_scope: Option<Scope>,
-    ) {
-        let mut expr = expr;
-        loop {
-            // Note: give all the expressions matching `ET` with the
-            // extended temporary lifetime, not just the innermost rvalue,
-            // because in codegen if we must compile e.g., `*rvalue()`
-            // into a temporary, we request the temporary scope of the
-            // outer expression.
-            visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope);
-
-            match expr.kind {
-                hir::ExprKind::AddrOf(_, _, ref subexpr)
-                | hir::ExprKind::Unary(hir::UnOp::Deref, ref subexpr)
-                | hir::ExprKind::Field(ref subexpr, _)
-                | hir::ExprKind::Index(ref subexpr, _) => {
-                    expr = &subexpr;
-                }
-                _ => {
-                    return;
-                }
+            hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
+                // FIXME(@dingxiangfei2009): choose call arguments here
+                // for candidacy for extended parameter rule application
+            }
+            hir::ExprKind::Index(..) => {
+                // FIXME(@dingxiangfei2009): select the indices
+                // as candidate for rvalue scope rules
             }
+            _ => {}
         }
     }
 }
@@ -821,14 +795,16 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
     }
 }
 
-fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
+/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
+/// in the case of closures, this will be redirected to the enclosing function.
+pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> ScopeTree {
     let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
     if typeck_root_def_id != def_id {
-        return tcx.region_scope_tree(typeck_root_def_id);
+        return region_scope_tree(tcx, typeck_root_def_id);
     }
 
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let scope_tree = if let Some(body_id) = tcx.hir().maybe_body_owned_by(id) {
+    if let Some(body_id) = tcx.hir().maybe_body_owned_by(id) {
         let mut visitor = RegionResolutionVisitor {
             tcx,
             scope_tree: ScopeTree::default(),
@@ -845,11 +821,5 @@ fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
         visitor.scope_tree
     } else {
         ScopeTree::default()
-    };
-
-    tcx.arena.alloc(scope_tree)
-}
-
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers { region_scope_tree, ..*providers };
+    }
 }
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 20456cc427c..01a76ce5586 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -75,7 +75,6 @@
 use crate::check::dropck;
 use crate::check::FnCtxt;
 use crate::mem_categorization as mc;
-use crate::middle::region;
 use crate::outlives::outlives_bounds::InferCtxtExt as _;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_hir as hir;
@@ -219,8 +218,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 pub struct RegionCtxt<'a, 'tcx> {
     pub fcx: &'a FnCtxt<'a, 'tcx>,
 
-    pub region_scope_tree: &'tcx region::ScopeTree,
-
     outlives_environment: OutlivesEnvironment<'tcx>,
 
     // id of innermost fn body id
@@ -247,11 +244,9 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
         Subject(subject): Subject,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RegionCtxt<'a, 'tcx> {
-        let region_scope_tree = fcx.tcx.region_scope_tree(subject);
         let outlives_environment = OutlivesEnvironment::new(param_env);
         RegionCtxt {
             fcx,
-            region_scope_tree,
             body_id: initial_body_id,
             body_owner: subject,
             subject_def_id: subject,
diff --git a/compiler/rustc_typeck/src/check/rvalue_scopes.rs b/compiler/rustc_typeck/src/check/rvalue_scopes.rs
new file mode 100644
index 00000000000..22c9e796107
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/rvalue_scopes.rs
@@ -0,0 +1,83 @@
+use super::FnCtxt;
+use hir::def_id::DefId;
+use hir::Node;
+use rustc_hir as hir;
+use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
+use rustc_middle::ty::RvalueScopes;
+
+/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
+/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
+/// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
+/// statement.
+///
+/// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
+/// `<rvalue>` as `blk_id`:
+///
+/// ```text
+///     ET = *ET
+///        | ET[...]
+///        | ET.f
+///        | (ET)
+///        | <rvalue>
+/// ```
+///
+/// Note: ET is intended to match "rvalues or places based on rvalues".
+fn record_rvalue_scope_rec(
+    rvalue_scopes: &mut RvalueScopes,
+    mut expr: &hir::Expr<'_>,
+    lifetime: Option<Scope>,
+) {
+    loop {
+        // Note: give all the expressions matching `ET` with the
+        // extended temporary lifetime, not just the innermost rvalue,
+        // because in codegen if we must compile e.g., `*rvalue()`
+        // into a temporary, we request the temporary scope of the
+        // outer expression.
+
+        rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime);
+
+        match expr.kind {
+            hir::ExprKind::AddrOf(_, _, subexpr)
+            | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
+            | hir::ExprKind::Field(subexpr, _)
+            | hir::ExprKind::Index(subexpr, _) => {
+                expr = subexpr;
+            }
+            _ => {
+                return;
+            }
+        }
+    }
+}
+fn record_rvalue_scope(
+    rvalue_scopes: &mut RvalueScopes,
+    expr: &hir::Expr<'_>,
+    candidate: &RvalueCandidateType,
+) {
+    debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
+    match candidate {
+        RvalueCandidateType::Borrow { lifetime, .. }
+        | RvalueCandidateType::Pattern { lifetime, .. } => {
+            record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime)
+        } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
+    }
+}
+
+pub fn resolve_rvalue_scopes<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    scope_tree: &'a ScopeTree,
+    def_id: DefId,
+) -> RvalueScopes {
+    let tcx = &fcx.tcx;
+    let hir_map = tcx.hir();
+    let mut rvalue_scopes = RvalueScopes::new();
+    debug!("start resolving rvalue scopes, def_id={def_id:?}");
+    debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
+    for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
+        let Some(Node::Expr(expr)) = hir_map.find(hir_id) else {
+            bug!("hir node does not exist")
+        };
+        record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
+    }
+    rvalue_scopes
+}
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 583958ade62..16096ea3d74 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -71,6 +71,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         wbcx.visit_user_provided_sigs();
         wbcx.visit_generator_interior_types();
 
+        wbcx.typeck_results.region_scope_tree =
+            mem::take(&mut self.typeck_results.borrow_mut().region_scope_tree);
+        wbcx.typeck_results.rvalue_scopes =
+            mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
+
         let used_trait_imports =
             mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 09f9c05b4fc..e2b82f9fd02 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -3,7 +3,9 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::has_iter_method;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
+use clippy_utils::{
+    contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq,
+};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -27,12 +29,7 @@ pub(super) fn check<'tcx>(
     body: &'tcx Expr<'_>,
     expr: &'tcx Expr<'_>,
 ) {
-    if let Some(higher::Range {
-        start: Some(start),
-        ref end,
-        limits,
-    }) = higher::Range::hir(arg)
-    {
+    if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::Range::hir(arg) {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
             let mut visitor = VarVisitor {
@@ -58,7 +55,11 @@ pub(super) fn check<'tcx>(
                 // ensure that the indexed variable was declared before the loop, see #601
                 if let Some(indexed_extent) = indexed_extent {
                     let parent_def_id = cx.tcx.hir().get_parent_item(expr.hir_id);
-                    let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
+                    let parent_body_id = cx
+                        .tcx
+                        .hir()
+                        .body_owned_by(cx.tcx.hir().local_def_id_to_hir_id(parent_def_id));
+                    let region_scope_tree = &cx.tcx.typeck_body(parent_body_id).region_scope_tree;
                     let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
                     if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
                         return;
@@ -107,17 +108,22 @@ pub(super) fn check<'tcx>(
                         }
                     }
 
-                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
+                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty)
+                    {
                         String::new()
-                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
+                    } else if visitor.indexed_mut.contains(&indexed)
+                        && contains_name(indexed, take_expr)
+                    {
                         return;
                     } else {
                         match limits {
                             ast::RangeLimits::Closed => {
                                 let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
                                 format!(".take({})", take_expr + sugg::ONE)
-                            },
-                            ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, take_expr.span, "..")),
+                            }
+                            ast::RangeLimits::HalfOpen => {
+                                format!(".take({})", snippet(cx, take_expr.span, ".."))
+                            }
                         }
                     }
                 } else {
@@ -143,7 +149,10 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
+                        &format!(
+                            "the loop variable `{}` is used to index `{}`",
+                            ident.name, indexed
+                        ),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -152,7 +161,10 @@ pub(super) fn check<'tcx>(
                                     (pat.span, format!("({}, <item>)", ident.name)),
                                     (
                                         arg.span,
-                                        format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
+                                        format!(
+                                            "{}.{}().enumerate(){}{}",
+                                            indexed, method, method_1, method_2
+                                        ),
                                     ),
                                 ],
                             );
@@ -169,7 +181,10 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed),
+                        &format!(
+                            "the loop variable `{}` is only used to index `{}`",
+                            ident.name, indexed
+                        ),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -246,7 +261,12 @@ struct VarVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
-    fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
+    fn check(
+        &mut self,
+        idx: &'tcx Expr<'_>,
+        seqexpr: &'tcx Expr<'_>,
+        expr: &'tcx Expr<'_>,
+    ) -> bool {
         if_chain! {
             // the indexed container is referenced by a name
             if let ExprKind::Path(ref seqpath) = seqexpr.kind;
@@ -262,7 +282,16 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                 match res {
                     Res::Local(hir_id) => {
                         let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
-                        let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id).unwrap();
+                        let parent_body_id = self.cx
+                            .tcx
+                            .hir()
+                            .body_owned_by(self.cx.tcx.hir().local_def_id_to_hir_id(parent_def_id));
+                        let extent = self.cx
+                            .tcx
+                            .typeck_body(parent_body_id)
+                            .region_scope_tree
+                            .var_scope(hir_id.local_id)
+                            .unwrap();
                         if index_used_directly {
                             self.indexed_directly.insert(
                                 seqvar.segments[0].ident.name,
@@ -331,13 +360,13 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                 self.visit_expr(lhs);
                 self.prefer_mutable = false;
                 self.visit_expr(rhs);
-            },
+            }
             ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
                 if mutbl == Mutability::Mut {
                     self.prefer_mutable = true;
                 }
                 self.visit_expr(expr);
-            },
+            }
             ExprKind::Call(f, args) => {
                 self.visit_expr(f);
                 for expr in args {
@@ -350,10 +379,11 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     }
                     self.visit_expr(expr);
                 }
-            },
+            }
             ExprKind::MethodCall(_, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
+                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args)
+                {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
@@ -362,11 +392,11 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     }
                     self.visit_expr(expr);
                 }
-            },
+            }
             ExprKind::Closure(_, _, body_id, ..) => {
                 let body = self.cx.tcx.hir().body(body_id);
                 self.visit_expr(&body.value);
-            },
+            }
             _ => walk_expr(self, expr),
         }
         self.prefer_mutable = old;
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 1ab7f52110c..db32b8d740b 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -5,7 +5,9 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{
+    Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, Symbol};
@@ -139,27 +141,31 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(
-            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
-            BodyOwnerKind::Closure
-        ) {
+        if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
+        {
             self.bindings.push(FxHashMap::default());
         }
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(
-            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
-            BodyOwnerKind::Closure
-        ) {
+        if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
+        {
             self.bindings.pop();
         }
     }
 }
 
-fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
-    let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
+fn is_shadow(
+    cx: &LateContext<'_>,
+    owner: LocalDefId,
+    first: ItemLocalId,
+    second: ItemLocalId,
+) -> bool {
+    let scope_tree = &cx
+        .tcx
+        .typeck_body(cx.tcx.hir().body_owned_by(cx.tcx.hir().local_def_id_to_hir_id(owner)))
+        .region_scope_tree;
     let first_scope = scope_tree.var_scope(first).unwrap();
     let second_scope = scope_tree.var_scope(second).unwrap();
     scope_tree.is_subscope_of(second_scope, first_scope)
@@ -174,15 +180,16 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
                 snippet(cx, expr.span, "..")
             );
             (SHADOW_SAME, msg)
-        },
+        }
         Some(expr) if is_local_used(cx, expr, shadowed) => {
             let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
             (SHADOW_REUSE, msg)
-        },
+        }
         _ => {
-            let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
+            let msg =
+                format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
             (SHADOW_UNRELATED, msg)
-        },
+        }
     };
     span_lint_and_note(
         cx,
@@ -211,14 +218,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
         expr = match expr.kind {
             ExprKind::Box(e)
             | ExprKind::AddrOf(_, _, e)
-            | ExprKind::Block(
-                &Block {
-                    stmts: [],
-                    expr: Some(e),
-                    ..
-                },
-                _,
-            )
+            | ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _)
             | ExprKind::Unary(UnOp::Deref, e) => e,
             ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
             _ => break false,