diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index 47d231603d33b..7d85579325751 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -184,7 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Declare the bindings, which may create a source scope. let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree); - this.push_scope((*remainder_scope, source_info)); + this.push_scope(*remainder_scope); let_scope_stack.push(remainder_scope); let visibility_scope = @@ -242,7 +242,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.block_context.push(BlockFrame::Statement { ignores_expr_result }); // Enter the remainder scope, i.e., the bindings' destruction scope. - this.push_scope((*remainder_scope, source_info)); + this.push_scope(*remainder_scope); let_scope_stack.push(remainder_scope); // Declare the bindings, which may create a source scope. @@ -346,7 +346,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Finally, we pop all the let scopes before exiting out from the scope of block // itself. for scope in let_scope_stack.into_iter().rev() { - block = this.pop_scope((*scope, source_info), block).into_block(); + block = this.pop_scope(*scope, block).into_block(); } // Restore the original source scope. this.source_scope = outer_source_scope; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index dd36411658305..ea484bd05878b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -726,7 +726,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This can be `None` if the expression's temporary scope was extended so that it can be // borrowed by a `const` or `static`. In that case, it's never dropped. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp); + this.schedule_drop_storage(upvar_span, temp_lifetime, temp); + this.schedule_drop_value(upvar_span, temp_lifetime, temp); } block.and(Operand::Move(Place::from(temp))) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index 55296c647c819..80d0e061487a7 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; -use crate::builder::scope::{DropKind, LintLevel}; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -120,7 +120,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `bar(&foo())` or anything within a block will keep the // regular drops just like runtime code. if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage); + this.schedule_drop_storage(expr_span, temp_lifetime, temp); } } } @@ -128,7 +128,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.expr_into_dest(temp_place, block, expr_id).into_block(); if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); + this.schedule_drop_value(expr_span, temp_lifetime, temp); } if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible { diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index f70416b2cf867..109f4de2698a4 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -28,7 +28,7 @@ use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::matches::buckets::PartitionedCandidates; use crate::builder::matches::user_ty::ProjectedUserTypesNode; -use crate::builder::scope::{DropKind, LintLevel}; +use crate::builder::scope::LintLevel; use crate::builder::{ BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, }; @@ -791,7 +791,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && matches!(schedule_drop, ScheduleDrops::Yes) { - self.schedule_drop(span, region_scope, local_id, DropKind::Storage); + self.schedule_drop_storage(span, region_scope, local_id); } let local_info = self.local_decls[local_id].local_info.as_mut().unwrap_crate_local(); if let LocalInfo::User(BindingForm::Var(var_info)) = &mut **local_info { @@ -808,7 +808,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let local_id = self.var_local_id(var, for_guard); if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) { - self.schedule_drop(span, region_scope, local_id, DropKind::Value); + self.schedule_drop_value(span, region_scope, local_id); } } diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 378e2e618fb93..b6478fc9c8deb 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -42,7 +42,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol}; use crate::builder::expr::as_place::PlaceBuilder; -use crate::builder::scope::{DropKind, LintLevel}; +use crate::builder::scope::LintLevel; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, @@ -955,11 +955,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = Place::from(local); // Make sure we drop (parts of) the argument even when not matched on. - self.schedule_drop( + self.schedule_drop_value( param.pat.as_ref().map_or(expr_span, |pat| pat.span), argument_scope, local, - DropKind::Value, ); let Some(ref pat) = param.pat else { diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 84abb6ca70e70..2197bbeab25cf 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -162,7 +162,7 @@ struct DropData { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum DropKind { +enum DropKind { Value, Storage, ForLint, @@ -488,11 +488,11 @@ impl<'tcx> Scopes<'tcx> { } } - fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) { + fn push_scope(&mut self, region_scope: region::Scope, vis_scope: SourceScope) { debug!("push_scope({:?})", region_scope); self.scopes.push(Scope { source_scope: vis_scope, - region_scope: region_scope.0, + region_scope, drops: vec![], moved_locals: vec![], cached_unwind_block: None, @@ -500,13 +500,13 @@ impl<'tcx> Scopes<'tcx> { }); } - fn pop_scope(&mut self, region_scope: (region::Scope, SourceInfo)) -> Scope { + fn pop_scope(&mut self, region_scope: region::Scope) { let scope = self.scopes.pop().unwrap(); - assert_eq!(scope.region_scope, region_scope.0); - scope + assert_eq!(scope.region_scope, region_scope); } - fn scope_index(&self, region_scope: region::Scope, span: Span) -> usize { + /// Returns the position in the scope stack of `region_scope`. + fn stack_index(&self, region_scope: region::Scope, span: Span) -> usize { self.scopes .iter() .rposition(|scope| scope.region_scope == region_scope) @@ -681,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { #[instrument(skip(self, f), level = "debug")] pub(crate) fn in_scope( &mut self, - region_scope: (region::Scope, SourceInfo), + (region_scope, source_info): (region::Scope, SourceInfo), lint_level: LintLevel, f: F, ) -> BlockAnd @@ -692,7 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let LintLevel::Explicit(current_hir_id) = lint_level { let parent_id = self.source_scopes[source_scope].local_data.as_ref().unwrap_crate_local().lint_root; - self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id); + self.maybe_new_source_scope(source_info.span, current_hir_id, parent_id); } self.push_scope(region_scope); let mut block; @@ -721,7 +721,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. - pub(crate) fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) { + pub(crate) fn push_scope(&mut self, region_scope: region::Scope) { self.scopes.push_scope(region_scope, self.source_scope); } @@ -730,13 +730,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// This must match 1-to-1 with `push_scope`. pub(crate) fn pop_scope( &mut self, - region_scope: (region::Scope, SourceInfo), + region_scope: region::Scope, mut block: BasicBlock, ) -> BlockAnd<()> { debug!("pop_scope({:?}, {:?})", region_scope, block); block = self.leave_top_scope(block); - self.scopes.pop_scope(region_scope); block.unit() @@ -804,7 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let region_scope = self.scopes.breakable_scopes[break_index].region_scope; - let scope_index = self.scopes.scope_index(region_scope, span); + let stack_index = self.scopes.stack_index(region_scope, span); let drops = if destination.is_some() { &mut self.scopes.breakable_scopes[break_index].break_drops } else { @@ -822,7 +821,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let mut drop_idx = ROOT_NODE; - for scope in &self.scopes.scopes[scope_index + 1..] { + for scope in &self.scopes.scopes[stack_index + 1..] { for drop in &scope.drops { drop_idx = drops.add_drop(*drop, drop_idx); } @@ -1007,9 +1006,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.block_context.pop(); let discr = self.temp(discriminant_ty, source_info.span); - let scope_index = self + let stack_index = self .scopes - .scope_index(self.scopes.const_continuable_scopes[break_index].region_scope, span); + .stack_index(self.scopes.const_continuable_scopes[break_index].region_scope, span); let scope = &mut self.scopes.const_continuable_scopes[break_index]; self.cfg.push_assign(block, source_info, discr, rvalue); let drop_and_continue_block = self.cfg.start_new_block(); @@ -1022,7 +1021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let drops = &mut scope.const_continue_drops; - let drop_idx = self.scopes.scopes[scope_index + 1..] + let drop_idx = self.scopes.scopes[stack_index + 1..] .iter() .flat_map(|scope| &scope.drops) .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); @@ -1032,10 +1031,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(imaginary_target, source_info, TerminatorKind::UnwindResume); let region_scope = scope.region_scope; - let scope_index = self.scopes.scope_index(region_scope, span); + let stack_index = self.scopes.stack_index(region_scope, span); let mut drops = DropTree::new(); - let drop_idx = self.scopes.scopes[scope_index + 1..] + let drop_idx = self.scopes.scopes[stack_index + 1..] .iter() .flat_map(|scope| &scope.drops) .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); @@ -1066,14 +1065,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .unwrap_or_else(|| span_bug!(source_info.span, "no if-then scope found")); let target = if_then_scope.region_scope; - let scope_index = self.scopes.scope_index(target, source_info.span); + let stack_index = self.scopes.stack_index(target, source_info.span); // Upgrade `if_then_scope` to `&mut`. let if_then_scope = self.scopes.if_then_scope.as_mut().expect("upgrading & to &mut"); let mut drop_idx = ROOT_NODE; let drops = &mut if_then_scope.else_drops; - for scope in &self.scopes.scopes[scope_index + 1..] { + for scope in &self.scopes.scopes[stack_index + 1..] { for drop in &scope.drops { drop_idx = drops.add_drop(*drop, drop_idx); } @@ -1390,47 +1389,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Scheduling drops // ================ - pub(crate) fn schedule_drop_storage_and_value( - &mut self, - span: Span, - region_scope: region::Scope, - local: Local, - ) { - self.schedule_drop(span, region_scope, local, DropKind::Storage); - self.schedule_drop(span, region_scope, local, DropKind::Value); - } - /// Indicates that `place` should be dropped on exit from `region_scope`. /// /// When called with `DropKind::Storage`, `place` shouldn't be the return /// place, or a function parameter. - pub(crate) fn schedule_drop( + fn schedule_drop( &mut self, span: Span, region_scope: region::Scope, local: Local, drop_kind: DropKind, ) { - let needs_drop = match drop_kind { - DropKind::Value | DropKind::ForLint => { - if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { - return; - } - true - } - DropKind::Storage => { - if local.index() <= self.arg_count { - span_bug!( - span, - "`schedule_drop` called with body argument {:?} \ - but its storage does not require a drop", - local, - ) - } - false - } - }; - // When building drops, we try to cache chains of drops to reduce the // number of `DropTree::add_drop` calls. This, however, means that // whenever we add a drop into a scope which already had some entries @@ -1477,7 +1446,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // path, we only need to invalidate the cache for drops that happen on // the unwind or coroutine drop paths. This means that for // non-coroutines we don't need to invalidate caches for `DropKind::Storage`. - let invalidate_caches = needs_drop || self.coroutine.is_some(); + let invalidate_caches = match drop_kind { + DropKind::Value | DropKind::ForLint => true, + DropKind::Storage => self.coroutine.is_some(), + }; for scope in self.scopes.scopes.iter_mut().rev() { if invalidate_caches { scope.invalidate_cache(); @@ -1501,6 +1473,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } + /// Indicates that `place` should be marked `StorageDead` on exit from `region_scope`. + /// + /// `place` must not be the return place, or a function parameter. + pub(crate) fn schedule_drop_storage( + &mut self, + span: Span, + region_scope: region::Scope, + local: Local, + ) { + if local.index() <= self.arg_count { + span_bug!( + span, + "`schedule_drop` called with body argument {:?} \ + but its storage does not require a drop", + local, + ) + } + self.schedule_drop(span, region_scope, local, DropKind::Storage); + } + + /// Indicates that `place` should be dropped on exit from `region_scope`. + pub(crate) fn schedule_drop_value( + &mut self, + span: Span, + region_scope: region::Scope, + local: Local, + ) { + if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { + return; + } + self.schedule_drop(span, region_scope, local, DropKind::Value); + } + /// Schedule emission of a backwards incompatible drop lint hint. /// Applicable only to temporary values for now. #[instrument(level = "debug", skip(self))] @@ -1512,28 +1517,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { // Note that we are *not* gating BIDs here on whether they have significant destructor. // We need to know all of them so that we can capture potential borrow-checking errors. - for scope in self.scopes.scopes.iter_mut().rev() { - // Since we are inserting linting MIR statement, we have to invalidate the caches - scope.invalidate_cache(); - if scope.region_scope == region_scope { - let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree); - let scope_end = self.tcx.sess.source_map().end_point(region_scope_span); - - scope.drops.push(DropData { - source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, - local, - kind: DropKind::ForLint, - }); - - return; - } - } - span_bug!( - span, - "region scope {:?} not in scope to drop {:?} for linting", - region_scope, - local - ); + self.schedule_drop(span, region_scope, local, DropKind::ForLint); } /// Indicates that the "local operand" stored in `local` is @@ -1611,7 +1595,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// It is possible to unwind to some ancestor scope if some drop panics as /// the program breaks out of a if-then scope. fn diverge_cleanup_target(&mut self, target_scope: region::Scope, span: Span) -> DropIdx { - let target = self.scopes.scope_index(target_scope, span); + let target = self.scopes.stack_index(target_scope, span); let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] .iter() .enumerate() @@ -1674,7 +1658,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.coroutine.is_some(), "diverge_dropline_target is valid only for coroutine" ); - let target = self.scopes.scope_index(target_scope, span); + let target = self.scopes.stack_index(target_scope, span); let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] .iter() .enumerate()