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, @@ -223,15 +223,12 @@ pub struct ScopeTree { /// Maps from a `NodeId` to the associated destruction scope (if any). destruction_scopes: FxIndexMap, - /// `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>, + /// 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, /// 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, } +/// 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 }, + Pattern { target: hir::ItemLocalId, lifetime: Option }, +} + #[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) { - 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 { - // 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> 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> 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 1b466910633..6b92a4c0a2e 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, 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>>, @@ -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>, +} + +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 { + // 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) { + 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>, - region_scope_tree: &'tcx region::ScopeTree, + rvalue_scopes: &'a RvalueScopes, expr_count: usize, kind: hir::GeneratorKind, prev_unresolved_span: Option, @@ -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 similarity index 93% rename from compiler/rustc_passes/src/region.rs rename to 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, ) { 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 - /// `` as `blk_id`: - /// - /// ```text - /// ET = *ET - /// | ET[...] - /// | ET.f - /// | (ET) - /// | - /// ``` - /// - /// 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, - ) { - 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 +/// `` as `blk_id`: +/// +/// ```text +/// ET = *ET +/// | ET[...] +/// | ET.f +/// | (ET) +/// | +/// ``` +/// +/// 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, +) { + 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, ""); 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!("({}, )", 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,