From a7b304be8c5aed3236881504594ce5b294f9a851 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 10 May 2020 17:58:53 +0100 Subject: [PATCH 1/2] Schedule drops sooner in MIR construction --- src/librustc_mir_build/build/block.rs | 10 +- .../build/expr/as_rvalue.rs | 11 +- src/librustc_mir_build/build/expr/as_temp.rs | 6 +- src/librustc_mir_build/build/expr/into.rs | 101 ++-- src/librustc_mir_build/build/into.rs | 11 +- src/librustc_mir_build/build/matches/mod.rs | 105 +---- src/librustc_mir_build/build/mod.rs | 24 +- src/librustc_mir_build/build/scope.rs | 169 ++++++- .../rustc.main.ElaborateDrops.before.mir | 2 +- .../rustc.test.ElaborateDrops.before.mir | 20 +- .../rustc.move_out_by_subslice.mir_map.0.mir | 22 +- .../rustc.move_out_from_end.mir_map.0.mir | 22 +- src/test/ui/drop/dynamic-drop-async.rs | 165 ++++--- src/test/ui/drop/dynamic-drop.rs | 437 +++++++++++------- 14 files changed, 711 insertions(+), 394 deletions(-) diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index fa783ddcf409a..3a215e8a54605 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -3,6 +3,7 @@ use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_span::Span; @@ -10,6 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn ast_block( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ast_block: &'tcx hir::Block<'tcx>, source_info: SourceInfo, @@ -26,9 +28,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { - this.in_breakable_scope(None, destination, span, |this| { + this.in_breakable_scope(None, destination, scope, span, |this| { Some(this.ast_block_stmts( destination, + scope, block, span, stmts, @@ -37,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )) }) } else { - this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) + this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode) } }) }) @@ -46,6 +49,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn ast_block_stmts( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, span: Span, stmts: Vec>, @@ -181,7 +185,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span }); - unpack!(block = this.into(destination, block, expr)); + unpack!(block = this.into(destination, scope, block, expr)); let popped = this.block_context.pop(); assert!(popped.map_or(false, |bf| bf.is_tail_expr())); diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs index d934ba1dc841e..ef74e9f6e194f 100644 --- a/src/librustc_mir_build/build/expr/as_rvalue.rs +++ b/src/librustc_mir_build/build/expr/as_rvalue.rs @@ -111,10 +111,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); - // initialize the box contents: + // Initialize the box contents. No scope is needed since the + // `Box` is already scheduled to be dropped. unpack!( - block = - this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) + block = this.into( + this.hir.tcx().mk_place_deref(Place::from(result)), + None, + block, + value, + ) ); block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs index d82abd8776719..e59220032fc92 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/src/librustc_mir_build/build/expr/as_temp.rs @@ -101,11 +101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.into(temp_place, block, expr)); - - if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); - } + unpack!(block = this.into(temp_place, temp_lifetime, block, expr)); block.and(temp) } diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index 8734d39a6d07b..81092854e8781 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -1,10 +1,12 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; +use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; @@ -14,13 +16,19 @@ use rustc_target::spec::abi::Abi; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + /// If a `drop_scope` is provided, `destination` is scheduled to be dropped + /// in `scope` once it has been initialized. crate fn into_expr( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, expr: Expr<'tcx>, ) -> BlockAnd<()> { - debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr); + debug!( + "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})", + destination, scope, block, expr + ); // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to @@ -35,6 +43,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; + let schedule_drop = move |this: &mut Self| { + if let Some(drop_scope) = scope { + let local = + destination.as_local().expect("cannot schedule drop of non-Local place"); + this.schedule_drop(expr_span, drop_scope, local, DropKind::Value); + } + }; + if !expr_is_block_or_scope { this.block_context.push(BlockFrame::SubExpr); } @@ -42,13 +58,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let block_and = match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, |this| this.into(destination, block, value)) + this.in_scope(region_scope, lint_level, |this| { + this.into(destination, scope, block, value) + }) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, block, ast_block, source_info) + this.ast_block(destination, scope, block, ast_block, source_info) } ExprKind::Match { scrutinee, arms } => { - this.match_expr(destination, expr_span, block, scrutinee, arms) + this.match_expr(destination, scope, expr_span, block, scrutinee, arms) } ExprKind::NeverToAny { source } => { let source = this.hir.mirror(source); @@ -63,6 +81,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. + schedule_drop(this); if is_call { block.unit() } else { @@ -138,26 +157,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Start the loop. this.cfg.goto(block, source_info, loop_block); - this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { - // conduct the test, if necessary - let body_block = this.cfg.start_new_block(); - this.cfg.terminate( - loop_block, - source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, - ); - this.diverge_from(loop_block); - - // The “return” value of the loop body must always be an unit. We therefore - // introduce a unit temporary as the destination for the loop body. - let tmp = this.get_unit_temp(); - // Execute the body, branching back to the test. - let body_block_end = unpack!(this.into(tmp, body_block, body)); - this.cfg.goto(body_block_end, source_info, loop_block); - - // Loops are only exited by `break` expressions. - None - }) + this.in_breakable_scope( + Some(loop_block), + destination, + scope, + expr_span, + move |this| { + // conduct the test, if necessary + let body_block = this.cfg.start_new_block(); + this.cfg.terminate( + loop_block, + source_info, + TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + ); + this.diverge_from(loop_block); + + // The “return” value of the loop body must always be an unit. We therefore + // introduce a unit temporary as the destination for the loop body. + let tmp = this.get_unit_temp(); + // Execute the body, branching back to the test. + // We don't need to provide a drop scope because `tmp` + // has type `()`. + let body_block_end = unpack!(this.into(tmp, None, body_block, body)); + this.cfg.goto(body_block_end, source_info, loop_block); + schedule_drop(this); + + // Loops are only exited by `break` expressions. + None + }, + ) } ExprKind::Call { ty, fun, args, from_hir_call } => { let intrinsic = match ty.kind { @@ -185,13 +213,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ptr_ty = ptr.ty; // Create an *internal* temp for the pointer, so that unsafety // checking won't complain about the raw pointer assignment. - let ptr_temp = this.local_decls.push(LocalDecl::with_source_info( - ptr_ty, - source_info, - ).internal()); + let ptr_temp = this + .local_decls + .push(LocalDecl::with_source_info(ptr_ty, source_info).internal()); let ptr_temp = Place::from(ptr_temp); - let block = unpack!(this.into(ptr_temp, block, ptr)); - this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val) + // No need for a scope, ptr_temp doesn't need drop + let block = unpack!(this.into(ptr_temp, None, block, ptr)); + // Maybe we should provide a scope here so that + // `move_val_init` wouldn't leak on panic even with an + // arbitrary `val` expression, but `schedule_drop`, + // borrowck and drop elaboration all prevent us from + // dropping `ptr_temp.deref()`. + this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val) } else { let args: Vec<_> = args .into_iter() @@ -221,10 +254,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); this.diverge_from(block); + schedule_drop(this); success.unit() } } - ExprKind::Use { source } => this.into(destination, block, source), + ExprKind::Use { source } => this.into(destination, scope, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that @@ -307,6 +341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, Rvalue::Aggregate(adt, fields), ); + schedule_drop(this); block.unit() } @@ -332,6 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { @@ -349,6 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } @@ -362,6 +399,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, ); this.generator_drop_cleanup(block); + schedule_drop(this); resume.unit() } @@ -391,6 +429,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } }; diff --git a/src/librustc_mir_build/build/into.rs b/src/librustc_mir_build/build/into.rs index 0baa0c833a514..6accee0ebe50e 100644 --- a/src/librustc_mir_build/build/into.rs +++ b/src/librustc_mir_build/build/into.rs @@ -6,6 +6,7 @@ use crate::build::{BlockAnd, Builder}; use crate::hair::*; +use rustc_middle::middle::region; use rustc_middle::mir::*; pub(in crate::build) trait EvalInto<'tcx> { @@ -13,6 +14,7 @@ pub(in crate::build) trait EvalInto<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()>; } @@ -21,13 +23,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn into( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, expr: E, ) -> BlockAnd<()> where E: EvalInto<'tcx>, { - expr.eval_into(self, destination, block) + expr.eval_into(self, destination, scope, block) } } @@ -36,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { let expr = builder.hir.mirror(self); - builder.into_expr(destination, block, expr) + builder.into_expr(destination, scope, block, expr) } } @@ -48,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { - builder.into_expr(destination, block, self) + builder.into_expr(destination, scope, block, self) } } diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 1071a4c97df65..321a4173154a6 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -16,8 +16,8 @@ use rustc_index::bit_set::BitSet; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; -use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_span::Span; use rustc_target::abi::VariantIdx; use smallvec::{smallvec, SmallVec}; @@ -84,6 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn match_expr( &mut self, destination: Place<'tcx>, + destination_scope: Option, span: Span, mut block: BasicBlock, scrutinee: ExprRef<'tcx>, @@ -104,6 +105,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.lower_match_arms( destination, + destination_scope, scrutinee_place, scrutinee_span, arm_candidates, @@ -210,75 +212,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Lower the bindings, guards and arm bodies of a `match` expression. - /// - /// The decision tree should have already been created - /// (by [Builder::lower_match_tree]). - /// - /// `outer_source_info` is the SourceInfo for the whole match. - fn lower_match_arms( - &mut self, - destination: Place<'tcx>, - scrutinee_place: Place<'tcx>, - scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, - outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, - ) -> BlockAnd<()> { - let arm_end_blocks: Vec<_> = arm_candidates - .into_iter() - .map(|(arm, candidate)| { - debug!("lowering arm {:?}\ncanidate = {:?}", arm, candidate); - - let arm_source_info = self.source_info(arm.span); - let arm_scope = (arm.scope, arm_source_info); - self.in_scope(arm_scope, arm.lint_level, |this| { - let body = this.hir.mirror(arm.body.clone()); - let scope = this.declare_bindings( - None, - arm.span, - &arm.pattern, - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - let arm_block = this.bind_pattern( - outer_source_info, - candidate, - arm.guard.as_ref(), - &fake_borrow_temps, - scrutinee_span, - Some(arm.scope), - ); - - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } - - this.into(destination, arm_block, body) - }) - }) - .collect(); - - // all the arm blocks will rejoin here - let end_block = self.cfg.start_new_block(); - - for arm_block in arm_end_blocks { - self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); - } - - self.source_scope = outer_source_info.scope; - - end_block.unit() - } - /// Binds the variables and ascribes types for a given `match` arm or /// `let` binding. /// /// Also check if the guard matches, if it's provided. /// `arm_scope` should be `Some` if and only if this is called for a /// `match` arm. - fn bind_pattern( + crate fn bind_pattern( &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, @@ -362,13 +302,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -395,9 +336,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: hair::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, } => { + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -435,7 +377,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -681,7 +622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[derive(Debug)] -struct Candidate<'pat, 'tcx> { +pub(super) struct Candidate<'pat, 'tcx> { /// `Span` of the original pattern that gave rise to this candidate span: Span, @@ -1973,16 +1914,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, internal: false, is_block_tail: None, - local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode, - // hypothetically, `visit_primary_bindings` could try to unzip - // an outermost hir::Ty as we descend, matching up - // idents in pat; but complex w/ unclear UI payoff. - // Instead, just abandon providing diagnostic info. - opt_ty_info: None, - opt_match_place, - pat_span, - })))), + local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + binding_mode, + // hypothetically, `visit_primary_bindings` could try to unzip + // an outermost hir::Ty as we descend, matching up + // idents in pat; but complex w/ unclear UI payoff. + // Instead, just abandon providing diagnostic info. + opt_ty_info: None, + opt_match_place, + pat_span, + }, + )))), }; let for_arm_body = self.local_decls.push(local); self.var_debug_info.push(VarDebugInfo { @@ -2000,7 +1943,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, internal: false, is_block_tail: None, - local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))), + local_info: Some(box LocalInfo::User(ClearCrossCrate::Set( + BindingForm::RefForGuard, + ))), }); self.var_debug_info.push(VarDebugInfo { name, diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index b30b57ea9217a..de38b20b6d028 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -591,8 +591,12 @@ where let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + let return_block = unpack!(builder.in_breakable_scope( + None, + Place::return_place(), + Some(call_site_scope), + fn_end, + |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body( START_BLOCK, @@ -602,7 +606,8 @@ where &body.value, ) })) - })); + }, + )); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); @@ -611,6 +616,7 @@ where if let Some(unreachable_block) = builder.cached_unreachable_block { builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable); } + builder.unschedule_return_place_drop(); return_block.unit() })); @@ -641,7 +647,9 @@ fn construct_const<'a, 'tcx>( let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into_expr(Place::return_place(), block, expr)); + // We don't provide a scope because we can't unwind in constants, so won't + // need to drop the return place. + unpack!(block = builder.into_expr(Place::return_place(), None, block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -885,7 +893,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; self.local_decls[local].local_info = if let Some(kind) = self_binding { - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))) + Some(box LocalInfo::User(ClearCrossCrate::Set( + BindingForm::ImplicitSelf(*kind), + ))) } else { let binding_mode = ty::BindingMode::BindByValue(mutability); Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( @@ -920,7 +930,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(Place::return_place(), block, body) + let call_site = + region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite }; + self.into(Place::return_place(), Some(call_site), block, body) } fn set_correct_source_scope_for_arg( diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs index 710a41bc8fdb5..3514f417623a3 100644 --- a/src/librustc_mir_build/build/scope.rs +++ b/src/librustc_mir_build/build/scope.rs @@ -81,8 +81,9 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ +use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::hair::{Expr, ExprRef, LintLevel}; +use crate::hair::{Arm, Expr, ExprRef, LintLevel}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_index::vec::IndexVec; @@ -158,6 +159,8 @@ struct BreakableScope<'tcx> { /// The destination of the loop/block expression itself (i.e., where to put /// the result of a `break` or `return` expression) break_destination: Place<'tcx>, + /// The scope that the destination should have its drop scheduled in. + destination_scope: Option, /// Drops that happen on the `break`/`return` path. break_drops: DropTree, /// Drops that happen on the `continue` path. @@ -443,6 +446,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, loop_block: Option, break_destination: Place<'tcx>, + destination_scope: Option, span: Span, f: F, ) -> BlockAnd<()> @@ -453,17 +457,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = BreakableScope { region_scope, break_destination, + destination_scope, break_drops: DropTree::new(), continue_drops: loop_block.map(|_| DropTree::new()), }; + let continue_blocks = loop_block.map(|block| (block, self.diverge_cleanup())); self.scopes.breakable_scopes.push(scope); let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); - let break_block = self.build_exit_tree(breakable_scope.break_drops, None); breakable_scope.continue_drops.map(|drops| { - self.build_exit_tree(drops, loop_block); + self.build_exit_tree(drops, continue_blocks); }); + let break_block = self.build_exit_tree(breakable_scope.break_drops, None); match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), @@ -592,22 +598,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .rposition(|breakable_scope| breakable_scope.region_scope == scope) .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) }; - let (break_index, destination) = match target { + let (break_index, destination, dest_scope) = match target { BreakableTarget::Return => { let scope = &self.scopes.breakable_scopes[0]; if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } - (0, Some(scope.break_destination)) + (0, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Break(scope) => { let break_index = get_scope_index(scope); let scope = &self.scopes.breakable_scopes[break_index]; - (break_index, Some(scope.break_destination)) + (break_index, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Continue(scope) => { let break_index = get_scope_index(scope); - (break_index, None) + (break_index, None, None) } }; @@ -615,7 +621,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(value) = value { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.into(destination, block, value)); + unpack!(block = self.into(destination, dest_scope, block, value)); + dest_scope + .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap())); self.block_context.pop(); } else { self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) @@ -863,6 +871,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } + /// Unschedule a drop. Used for `break`, `return` and `match` expressions, + /// where `record_operands_moved` is not powerful enough. + /// + /// The given local is expected to have a value drop scheduled in the given + /// scope and for that drop to be the most recent thing scheduled in that + /// scope. + fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) { + if !self.hir.needs_drop(self.local_decls[local].ty) { + return; + } + for scope in self.scopes.scopes.iter_mut().rev() { + scope.invalidate_cache(); + + if scope.region_scope == region_scope { + let drop = scope.drops.pop(); + + match drop { + Some(DropData { local: removed_local, kind: DropKind::Value, .. }) + if removed_local == local => + { + return; + } + _ => bug!( + "found wrong drop, expected value drop of {:?}, found {:?}", + local, + drop, + ), + } + } + } + + bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local); + } + /// Indicates that the "local operand" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, @@ -1118,11 +1160,96 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block } + /// Lower the arms and guards of a match. + /// + /// The decision tree should have already been created (by + /// [Builder::lower_match_tree]). + /// + /// This is this module, and not in `build::matches` because we have to do + /// some careful scope manipulation to have the drop of the destination be + /// scheduled at the end of each arm and then cleared for the next arm. + crate fn lower_match_arms( + &mut self, + destination: Place<'tcx>, + destination_scope: Option, + scrutinee_place: Place<'tcx>, + scrutinee_span: Span, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + outer_source_info: SourceInfo, + fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + ) -> BlockAnd<()> { + if arm_candidates.is_empty() { + // If there are no arms to schedule drops, then we have to do it + // manually. + if let Some(scope) = destination_scope { + self.schedule_drop( + outer_source_info.span, + scope, + destination.as_local().unwrap(), + DropKind::Value, + ); + } + return self.cfg.start_new_block().unit(); + } + let mut first_arm = true; + let arm_end_blocks: Vec<_> = arm_candidates + .into_iter() + .map(|(arm, candidate)| { + debug!("lowering arm {:?}\ncanidate = {:?}", arm, candidate); + + if first_arm { + first_arm = false; + } else if let Some(scope) = destination_scope { + self.unschedule_drop(scope, destination.as_local().unwrap()); + } + + let arm_source_info = self.source_info(arm.span); + let arm_scope = (arm.scope, arm_source_info); + self.in_scope(arm_scope, arm.lint_level, |this| { + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.pattern, + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), + ); + + let arm_block = this.bind_pattern( + outer_source_info, + candidate, + arm.guard.as_ref(), + &fake_borrow_temps, + scrutinee_span, + Some(arm.scope), + ); + + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } + + this.into(destination, destination_scope, arm_block, body) + }) + }) + .collect(); + + // all the arm blocks will rejoin here + let end_block = self.cfg.start_new_block(); + + for arm_block in arm_end_blocks { + self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); + } + + self.source_scope = outer_source_info.scope; + + end_block.unit() + } + /// Unschedules any drops in the top scope. /// /// This is only needed for `match` arm scopes, because they have one /// entrance per pattern, but only one exit. - crate fn clear_top_scope(&mut self, region_scope: region::Scope) { + pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) { let top_scope = self.scopes.scopes.last_mut().unwrap(); assert_eq!(top_scope.region_scope, region_scope); @@ -1130,6 +1257,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { top_scope.drops.clear(); top_scope.invalidate_cache(); } + + /// Unschedules the drop of the return place. + /// + /// If the return type of a function requires drop, then we schedule it + /// in the outermost scope so that it's dropped if there's a panic while + /// we drop any local variables. But we don't want to drop it if we + /// return normally. + crate fn unschedule_return_place_drop(&mut self) { + assert_eq!(self.scopes.scopes.len(), 1); + assert!(self.scopes.scopes[0].drops.len() <= 1); + self.scopes.scopes[0].drops.clear(); + } } /// Builds drops for `pop_scope` and `leave_top_scope`. @@ -1213,20 +1352,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build a drop tree for a breakable scope. /// /// If `continue_block` is `Some`, then the tree is for `continue` inside a - /// loop. Otherwise this is for `break` or `return`. + /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the + /// next drop in the case that the drop tree unwinds. This is needed + /// because the drop of the break destination has already been scheduled + /// but it hasn't been initialized on the `continue` paths. fn build_exit_tree( &mut self, mut drops: DropTree, - continue_block: Option, + continue_block: Option<(BasicBlock, DropIdx)>, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block; + blocks[ROOT_NODE] = continue_block.map(|(block, _)| block); drops.build_mir::(&mut self.cfg, &mut blocks); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = self.diverge_cleanup(); + let unwind_target = continue_block + .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { diff --git a/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir index 9d5b9be363d3f..3263bdd08d45a 100644 --- a/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir @@ -25,7 +25,7 @@ fn main() -> () { bb1: { _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + drop(_2) -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } bb2: { diff --git a/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir index f59d157d2971a..dc395cbeb4f45 100644 --- a/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> std::option::Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = std::option::Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = const as std::ops::Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = const as std::ops::Try>::into_result(move _4) -> [return: bb1, unwind: bb13]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // ty::Const // + ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result} // + val: Value(Scalar()) @@ -51,7 +51,7 @@ fn test() -> std::option::Option> { (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb7, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb3: { @@ -64,7 +64,7 @@ fn test() -> std::option::Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = const >::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = const >::from(move _9) -> [return: bb5, unwind: bb13]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // ty::Const // + ty: fn(std::option::NoneError) -> std::option::NoneError {>::from} // + val: Value(Scalar()) @@ -75,7 +75,7 @@ fn test() -> std::option::Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb6, unwind: bb13]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // ty::Const // + ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error} // + val: Value(Scalar()) @@ -87,13 +87,13 @@ fn test() -> std::option::Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb9, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 _0 = std::option::Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + drop(_1) -> [return: bb8, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb8: { @@ -114,14 +114,18 @@ fn test() -> std::option::Option> { } bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + drop(_0) -> bb14; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 } bb12 (cleanup): { - drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_1) -> bb14; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb13 (cleanup): { + drop(_2) -> bb14; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + } + + bb14 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir index d6478c628dee1..33c2cb78bd82e 100644 --- a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir @@ -28,7 +28,7 @@ fn move_out_by_subslice() -> () { // + span: $DIR/uniform_array_move_out.rs:11:18: 11:19 // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + drop(_3) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 } bb1: { @@ -44,18 +44,18 @@ fn move_out_by_subslice() -> () { // + span: $DIR/uniform_array_move_out.rs:11:25: 11:26 // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + drop(_5) -> [return: bb2, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 } bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_4) -> [return: bb3, unwind: bb7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb4, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb4: { @@ -70,12 +70,12 @@ fn move_out_by_subslice() -> () { // mir::Constant // + span: $DIR/uniform_array_move_out.rs:10:27: 13:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_6) -> [return: bb5, unwind: bb8]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb5: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb6: { @@ -84,18 +84,22 @@ fn move_out_by_subslice() -> () { } bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_2) -> bb8; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_1) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_4) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } bb10 (cleanup): { + drop(_2) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb11 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir index bba616de9a68e..9d4b5b57fc479 100644 --- a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir @@ -28,7 +28,7 @@ fn move_out_from_end() -> () { // + span: $DIR/uniform_array_move_out.rs:5:18: 5:19 // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + drop(_3) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 } bb1: { @@ -44,18 +44,18 @@ fn move_out_from_end() -> () { // + span: $DIR/uniform_array_move_out.rs:5:25: 5:26 // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + drop(_5) -> [return: bb2, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 } bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_4) -> [return: bb3, unwind: bb7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb4, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb4: { @@ -70,12 +70,12 @@ fn move_out_from_end() -> () { // mir::Constant // + span: $DIR/uniform_array_move_out.rs:4:24: 7:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_6) -> [return: bb5, unwind: bb8]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb5: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb6: { @@ -84,18 +84,22 @@ fn move_out_from_end() -> () { } bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_2) -> bb8; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_1) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_4) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } bb10 (cleanup): { + drop(_2) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb11 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index 88d36ab6aa664..acd4bff237ffa 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -46,6 +46,7 @@ impl Future for Defer { /// The `failing_op`-th operation will panic. struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -57,23 +58,28 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { - Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) } + fn new(failing_op: usize, name: &'static str) -> Self { + Allocator { + failing_op, + name, + cur_ops: Cell::new(0), + data: RefCell::new(vec![]), + } } - fn alloc(&self) -> impl Future> + '_ { + fn alloc(self: &Rc) -> impl Future + 'static { self.fallible_operation(); let mut data = self.data.borrow_mut(); let addr = data.len(); data.push(true); - Defer { ready: false, value: Some(Ptr(addr, self)) } + Defer { ready: false, value: Some(Ptr(addr, self.clone())) } } fn fallible_operation(&self) { self.cur_ops.set(self.cur_ops.get() + 1); @@ -86,11 +92,11 @@ impl Allocator { // Type that tracks whether it was dropped and can panic when it's created or // destroyed. -struct Ptr<'a>(usize, &'a Allocator); -impl<'a> Drop for Ptr<'a> { +struct Ptr(usize, Rc); +impl Drop for Ptr { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => panic!("double free at index {:?}", self.0), + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), ref mut d => *d = false, } @@ -114,7 +120,7 @@ async fn dynamic_drop(a: Rc, c: bool) { }; } -struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); +struct TwoPtrs(Ptr, Ptr); async fn struct_dynamic_drop(a: Rc, c0: bool, c1: bool, c: bool) { for i in 0..2 { let x; @@ -235,21 +241,62 @@ async fn move_ref_pattern(a: Rc) { a.alloc().await; } -fn run_test(cx: &mut Context<'_>, ref f: F) +async fn panic_after_return(a: Rc, c: bool) -> (Ptr,) { + a.alloc().await; + let p = a.alloc().await; + if c { + a.alloc().await; + let q = a.alloc().await; + // We use a return type that isn't used anywhere else to make sure that + // the return place doesn't incorrectly end up in the generator state. + return (a.alloc().await,); + } + (a.alloc().await,) +} + + +async fn panic_after_init_by_loop(a: Rc) { + a.alloc().await; + let p = a.alloc().await; + let q = loop { + a.alloc().await; + let r = a.alloc().await; + break a.alloc().await; + }; +} + +async fn panic_after_init_by_match_with_bindings_and_guard(a: Rc, b: bool) { + a.alloc().await; + let p = a.alloc().await; + let q = match a.alloc().await { + ref _x if b => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + } + _x => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + }, + }; +} + +fn run_test(cx: &mut Context<'_>, ref f: F, name: &'static str) where F: Fn(Rc) -> G, - G: Future, + G: Future, { for polls in 0.. { // Run without any panics to find which operations happen after the // penultimate `poll`. - let first_alloc = Rc::new(Allocator::new(usize::MAX)); + let first_alloc = Rc::new(Allocator::new(usize::MAX, name)); let mut fut = Box::pin(f(first_alloc.clone())); let mut ops_before_last_poll = 0; let mut completed = false; for _ in 0..polls { ops_before_last_poll = first_alloc.cur_ops.get(); - if let Poll::Ready(()) = fut.as_mut().poll(cx) { + if let Poll::Ready(_) = fut.as_mut().poll(cx) { completed = true; } } @@ -258,7 +305,7 @@ where // Start at `ops_before_last_poll` so that we will always be able to // `poll` the expected number of times. for failing_op in ops_before_last_poll..first_alloc.cur_ops.get() { - let alloc = Rc::new(Allocator::new(failing_op + 1)); + let alloc = Rc::new(Allocator::new(failing_op + 1, name)); let f = &f; let cx = &mut *cx; let result = panic::catch_unwind(panic::AssertUnwindSafe(move || { @@ -288,48 +335,58 @@ fn clone_waker(data: *const ()) -> RawWaker { RawWaker::new(data, &RawWakerVTable::new(clone_waker, drop, drop, drop)) } +macro_rules! run_test { + ($ctxt:expr, $e:expr) => { run_test($ctxt, $e, stringify!($e)); }; +} + fn main() { let waker = unsafe { Waker::from_raw(clone_waker(ptr::null())) }; let context = &mut Context::from_waker(&waker); - run_test(context, |a| dynamic_init(a, false)); - run_test(context, |a| dynamic_init(a, true)); - run_test(context, |a| dynamic_drop(a, false)); - run_test(context, |a| dynamic_drop(a, true)); - - run_test(context, |a| assignment(a, false, false)); - run_test(context, |a| assignment(a, false, true)); - run_test(context, |a| assignment(a, true, false)); - run_test(context, |a| assignment(a, true, true)); - - run_test(context, |a| array_simple(a)); - run_test(context, |a| vec_simple(a)); - run_test(context, |a| vec_unreachable(a)); - - run_test(context, |a| struct_dynamic_drop(a, false, false, false)); - run_test(context, |a| struct_dynamic_drop(a, false, false, true)); - run_test(context, |a| struct_dynamic_drop(a, false, true, false)); - run_test(context, |a| struct_dynamic_drop(a, false, true, true)); - run_test(context, |a| struct_dynamic_drop(a, true, false, false)); - run_test(context, |a| struct_dynamic_drop(a, true, false, true)); - run_test(context, |a| struct_dynamic_drop(a, true, true, false)); - run_test(context, |a| struct_dynamic_drop(a, true, true, true)); - - run_test(context, |a| field_assignment(a, false)); - run_test(context, |a| field_assignment(a, true)); - - run_test(context, |a| mixed_drop_and_nondrop(a)); - - run_test(context, |a| slice_pattern_one_of(a, 0)); - run_test(context, |a| slice_pattern_one_of(a, 1)); - run_test(context, |a| slice_pattern_one_of(a, 2)); - run_test(context, |a| slice_pattern_one_of(a, 3)); - - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(context, |a| subslice_pattern_reassign(a)); - - run_test(context, |a| move_ref_pattern(a)); + run_test!(context, |a| dynamic_init(a, false)); + run_test!(context, |a| dynamic_init(a, true)); + run_test!(context, |a| dynamic_drop(a, false)); + run_test!(context, |a| dynamic_drop(a, true)); + + run_test!(context, |a| assignment(a, false, false)); + run_test!(context, |a| assignment(a, false, true)); + run_test!(context, |a| assignment(a, true, false)); + run_test!(context, |a| assignment(a, true, true)); + + run_test!(context, |a| array_simple(a)); + run_test!(context, |a| vec_simple(a)); + run_test!(context, |a| vec_unreachable(a)); + + run_test!(context, |a| struct_dynamic_drop(a, false, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, true)); + + run_test!(context, |a| field_assignment(a, false)); + run_test!(context, |a| field_assignment(a, true)); + + run_test!(context, |a| mixed_drop_and_nondrop(a)); + + run_test!(context, |a| slice_pattern_one_of(a, 0)); + run_test!(context, |a| slice_pattern_one_of(a, 1)); + run_test!(context, |a| slice_pattern_one_of(a, 2)); + run_test!(context, |a| slice_pattern_one_of(a, 3)); + + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(context, |a| subslice_pattern_reassign(a)); + + run_test!(context, |a| move_ref_pattern(a)); + + run_test!(context, |a| panic_after_return(a, false)); + run_test!(context, |a| panic_after_return(a, true)); + run_test!(context, |a| panic_after_init_by_loop(a)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, true)); } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index d31736f142c3f..9df68fa6ae8a5 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -4,7 +4,6 @@ #![feature(generators, generator_trait, untagged_unions)] #![feature(move_ref_pattern)] #![feature(bindings_after_at)] - #![allow(unused_assignments)] #![allow(unused_variables)] @@ -19,6 +18,7 @@ struct InjectedFailure; struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -30,17 +30,18 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { + fn new(failing_op: usize, name: &'static str) -> Self { Allocator { failing_op: failing_op, cur_ops: Cell::new(0), - data: RefCell::new(vec![]) + data: RefCell::new(vec![]), + name, } } fn alloc(&self) -> Ptr<'_> { @@ -55,33 +56,17 @@ impl Allocator { data.push(true); Ptr(addr, self) } - // FIXME(#47949) Any use of this indicates a bug in rustc: we should never - // be leaking values in the cases here. - // - // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the - // `failing_op` is in the list of exception. - fn alloc_leaked(&self, exceptions: Vec) -> Ptr<'_> { - let ptr = self.alloc(); - - if exceptions.iter().any(|operation| *operation == self.failing_op) { - let mut data = self.data.borrow_mut(); - data[ptr.0] = false; - } - ptr - } } struct Ptr<'a>(usize, &'a Allocator); impl<'a> Drop for Ptr<'a> { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => { - panic!("double free at index {:?}", self.0) - } - ref mut d => *d = false + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), + ref mut d => *d = false, } - self.1.cur_ops.set(self.1.cur_ops.get()+1); + self.1.cur_ops.set(self.1.cur_ops.get() + 1); if self.1.cur_ops.get() == self.1.failing_op { panic!(InjectedFailure); @@ -179,11 +164,7 @@ fn generator(a: &Allocator, run_count: usize) { assert!(run_count < 4); let mut gen = || { - (a.alloc(), - yield a.alloc(), - a.alloc(), - yield a.alloc() - ); + (a.alloc(), yield a.alloc(), a.alloc(), yield a.alloc()); }; for _ in 0..run_count { Pin::new(&mut gen).resume(()); @@ -207,28 +188,40 @@ fn vec_unreachable(a: &Allocator) { } fn slice_pattern_first(a: &Allocator) { - let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; + let [_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_middle(a: &Allocator) { - let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; + let [_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_two(a: &Allocator) { - let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_last(a: &Allocator) { - let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_one_of(a: &Allocator, i: usize) { let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; let _x = match i { - 0 => { let [a, ..] = array; a } - 1 => { let [_, a, ..] = array; a } - 2 => { let [_, _, a, _] = array; a } - 3 => { let [_, _, _, a] = array; a } + 0 => { + let [a, ..] = array; + a + } + 1 => { + let [_, a, ..] = array; + a + } + 2 => { + let [_, _, a, _] = array; + a + } + 3 => { + let [_, _, _, a] = array; + a + } _ => panic!("unmatched"), }; } @@ -236,9 +229,9 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { fn subslice_pattern_from_end(a: &Allocator, arg: bool) { let a = [a.alloc(), a.alloc(), a.alloc()]; if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } @@ -250,45 +243,61 @@ fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { } if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } fn slice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc()]; - let[_, _x] = ar; + let [_, _x] = ar; ar = [a.alloc(), a.alloc()]; - let[.., _y] = ar; + let [.., _y] = ar; } fn subslice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _, _x] = ar; + let [_, _, _x] = ar; ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _y @ ..] = ar; + let [_, _y @ ..] = ar; } fn index_field_mixed_ends(a: &Allocator) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; - let[(_x, _), ..] = ar; - let[(_, _y), _] = ar; - let[_, (_, _w)] = ar; - let[.., (_z, _)] = ar; + let [(_x, _), ..] = ar; + let [(_, _y), _] = ar; + let [_, (_, _w)] = ar; + let [.., (_z, _)] = ar; } fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; match c { - 0 => { let[_x, ..] = ar; } - 1 => { let[_x, _, ..] = ar; } - 2 => { let[_x, _] = ar; } - 3 => { let[(_x, _), _, ..] = ar; } - 4 => { let[.., (_x, _)] = ar; } - 5 => { let[.., (_x, _), _] = ar; } - 6 => { let [_y @ ..] = ar; } - _ => { let [_y @ .., _] = ar; } + 0 => { + let [_x, ..] = ar; + } + 1 => { + let [_x, _, ..] = ar; + } + 2 => { + let [_x, _] = ar; + } + 3 => { + let [(_x, _), _, ..] = ar; + } + 4 => { + let [.., (_x, _)] = ar; + } + 5 => { + let [.., (_x, _), _] = ar; + } + 6 => { + let [_y @ ..] = ar; + } + _ => { + let [_y @ .., _] = ar; + } } } @@ -336,87 +345,160 @@ fn move_ref_pattern(a: &Allocator) { } fn panic_after_return(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let p = a.alloc(); - // FIXME (#47949) We leak values when we panic in a destructor after - // evaluating an expression with `rustc_mir::build::Builder::into`. - a.alloc_leaked(exceptions) + a.alloc() } } fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let q = a.alloc(); - // FIXME (#47949) - return a.alloc_leaked(exceptions); + return a.alloc(); } } fn panic_after_init(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_temp(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_by_loop(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = loop { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - break a.alloc_leaked(exceptions); + break a.alloc(); + }; +} + +fn panic_after_init_by_match(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let _ = loop { + let q = match b { + true => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + false => { + a.alloc(); + let r = a.alloc(); + break a.alloc(); + } + }; + return; + }; +} + +fn panic_after_init_by_match_with_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _ if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _ => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_ref_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + ref _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + ref _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_break_if(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = loop { + let r = a.alloc(); + break if b { + let s = a.alloc(); + a.alloc() + } else { + a.alloc() + }; }; } -fn run_test(mut f: F) - where F: FnMut(&Allocator) +fn run_test(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); - for failing_op in 1..first_alloc.cur_ops.get()+1 { - let alloc = Allocator::new(failing_op); + for failing_op in 1..first_alloc.cur_ops.get() + 1 { + let alloc = Allocator::new(failing_op, name); let alloc = &alloc; let f = panic::AssertUnwindSafe(&mut f); let result = panic::catch_unwind(move || { f.0(alloc); }); match result { - Ok(..) => panic!("test executed {} ops but now {}", - first_alloc.cur_ops.get(), alloc.cur_ops.get()), + Ok(..) => panic!( + "test executed {} ops but now {}", + first_alloc.cur_ops.get(), + alloc.cur_ops.get() + ), Err(e) => { if e.downcast_ref::().is_none() { panic::resume_unwind(e); @@ -426,98 +508,115 @@ fn run_test(mut f: F) } } -fn run_test_nopanic(mut f: F) - where F: FnMut(&Allocator) +fn run_test_nopanic(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); } +macro_rules! run_test { + ($e:expr) => { + run_test($e, stringify!($e)); + }; +} + fn main() { - run_test(|a| dynamic_init(a, false)); - run_test(|a| dynamic_init(a, true)); - run_test(|a| dynamic_drop(a, false)); - run_test(|a| dynamic_drop(a, true)); - - run_test(|a| assignment2(a, false, false)); - run_test(|a| assignment2(a, false, true)); - run_test(|a| assignment2(a, true, false)); - run_test(|a| assignment2(a, true, true)); - - run_test(|a| assignment1(a, false)); - run_test(|a| assignment1(a, true)); - - run_test(|a| array_simple(a)); - run_test(|a| vec_simple(a)); - run_test(|a| vec_unreachable(a)); - - run_test(|a| struct_dynamic_drop(a, false, false, false)); - run_test(|a| struct_dynamic_drop(a, false, false, true)); - run_test(|a| struct_dynamic_drop(a, false, true, false)); - run_test(|a| struct_dynamic_drop(a, false, true, true)); - run_test(|a| struct_dynamic_drop(a, true, false, false)); - run_test(|a| struct_dynamic_drop(a, true, false, true)); - run_test(|a| struct_dynamic_drop(a, true, true, false)); - run_test(|a| struct_dynamic_drop(a, true, true, true)); - - run_test(|a| field_assignment(a, false)); - run_test(|a| field_assignment(a, true)); - - run_test(|a| generator(a, 0)); - run_test(|a| generator(a, 1)); - run_test(|a| generator(a, 2)); - run_test(|a| generator(a, 3)); - - run_test(|a| mixed_drop_and_nondrop(a)); - - run_test(|a| slice_pattern_first(a)); - run_test(|a| slice_pattern_middle(a)); - run_test(|a| slice_pattern_two(a)); - run_test(|a| slice_pattern_last(a)); - run_test(|a| slice_pattern_one_of(a, 0)); - run_test(|a| slice_pattern_one_of(a, 1)); - run_test(|a| slice_pattern_one_of(a, 2)); - run_test(|a| slice_pattern_one_of(a, 3)); - - run_test(|a| subslice_pattern_from_end(a, true)); - run_test(|a| subslice_pattern_from_end(a, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(|a| slice_pattern_reassign(a)); - run_test(|a| subslice_pattern_reassign(a)); - - run_test(|a| index_field_mixed_ends(a)); - run_test(|a| subslice_mixed_min_lengths(a, 0)); - run_test(|a| subslice_mixed_min_lengths(a, 1)); - run_test(|a| subslice_mixed_min_lengths(a, 2)); - run_test(|a| subslice_mixed_min_lengths(a, 3)); - run_test(|a| subslice_mixed_min_lengths(a, 4)); - run_test(|a| subslice_mixed_min_lengths(a, 5)); - run_test(|a| subslice_mixed_min_lengths(a, 6)); - run_test(|a| subslice_mixed_min_lengths(a, 7)); - - run_test(|a| move_ref_pattern(a)); - - run_test(|a| { + run_test!(|a| dynamic_init(a, false)); + run_test!(|a| dynamic_init(a, true)); + run_test!(|a| dynamic_drop(a, false)); + run_test!(|a| dynamic_drop(a, true)); + + run_test!(|a| assignment2(a, false, false)); + run_test!(|a| assignment2(a, false, true)); + run_test!(|a| assignment2(a, true, false)); + run_test!(|a| assignment2(a, true, true)); + + run_test!(|a| assignment1(a, false)); + run_test!(|a| assignment1(a, true)); + + run_test!(|a| array_simple(a)); + run_test!(|a| vec_simple(a)); + run_test!(|a| vec_unreachable(a)); + + run_test!(|a| struct_dynamic_drop(a, false, false, false)); + run_test!(|a| struct_dynamic_drop(a, false, false, true)); + run_test!(|a| struct_dynamic_drop(a, false, true, false)); + run_test!(|a| struct_dynamic_drop(a, false, true, true)); + run_test!(|a| struct_dynamic_drop(a, true, false, false)); + run_test!(|a| struct_dynamic_drop(a, true, false, true)); + run_test!(|a| struct_dynamic_drop(a, true, true, false)); + run_test!(|a| struct_dynamic_drop(a, true, true, true)); + + run_test!(|a| field_assignment(a, false)); + run_test!(|a| field_assignment(a, true)); + + run_test!(|a| generator(a, 0)); + run_test!(|a| generator(a, 1)); + run_test!(|a| generator(a, 2)); + run_test!(|a| generator(a, 3)); + + run_test!(|a| mixed_drop_and_nondrop(a)); + + run_test!(|a| slice_pattern_first(a)); + run_test!(|a| slice_pattern_middle(a)); + run_test!(|a| slice_pattern_two(a)); + run_test!(|a| slice_pattern_last(a)); + run_test!(|a| slice_pattern_one_of(a, 0)); + run_test!(|a| slice_pattern_one_of(a, 1)); + run_test!(|a| slice_pattern_one_of(a, 2)); + run_test!(|a| slice_pattern_one_of(a, 3)); + + run_test!(|a| subslice_pattern_from_end(a, true)); + run_test!(|a| subslice_pattern_from_end(a, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(|a| slice_pattern_reassign(a)); + run_test!(|a| subslice_pattern_reassign(a)); + + run_test!(|a| index_field_mixed_ends(a)); + run_test!(|a| subslice_mixed_min_lengths(a, 0)); + run_test!(|a| subslice_mixed_min_lengths(a, 1)); + run_test!(|a| subslice_mixed_min_lengths(a, 2)); + run_test!(|a| subslice_mixed_min_lengths(a, 3)); + run_test!(|a| subslice_mixed_min_lengths(a, 4)); + run_test!(|a| subslice_mixed_min_lengths(a, 5)); + run_test!(|a| subslice_mixed_min_lengths(a, 6)); + run_test!(|a| subslice_mixed_min_lengths(a, 7)); + + run_test!(|a| move_ref_pattern(a)); + + run_test!(|a| { panic_after_return(a); }); - run_test(|a| { + run_test!(|a| { panic_after_return_expr(a); }); - run_test(|a| panic_after_init(a)); - run_test(|a| panic_after_init_temp(a)); - run_test(|a| panic_after_init_by_loop(a)); - - run_test(|a| bindings_after_at_dynamic_init_move(a, true)); - run_test(|a| bindings_after_at_dynamic_init_move(a, false)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); - - run_test_nopanic(|a| union1(a)); + run_test!(|a| panic_after_init(a)); + run_test!(|a| panic_after_init_temp(a)); + run_test!(|a| panic_after_init_by_loop(a)); + run_test!(|a| panic_after_init_by_match(a, false)); + run_test!(|a| panic_after_init_by_match(a, true)); + run_test!(|a| panic_after_init_by_match_with_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_break_if(a, false)); + run_test!(|a| panic_after_init_by_break_if(a, true)); + + run_test!(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, false)); + + run_test_nopanic(|a| union1(a), "|a| union1(a)"); } From 0ce2ce18fd9e99df3a5fdd2c61636036078364e6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 13 May 2020 18:22:38 +0100 Subject: [PATCH 2/2] Reduce the number of drops generated by mir lowering --- .../build/expr/as_rvalue.rs | 9 ++- src/librustc_mir_build/build/expr/into.rs | 7 +- src/librustc_mir_build/build/expr/stmt.rs | 8 +- src/librustc_mir_build/build/scope.rs | 61 +++++++-------- .../rustc.main.SimplifyCfg-initial.after.mir | 28 +++---- .../rustc.main.ElaborateDrops.before.mir | 28 +++---- .../rustc.main.ElaborateDrops.after.mir | 51 +------------ .../rustc.test.ElaborateDrops.after.mir | 48 +++++------- .../rustc.main.ElaborateDrops.after.mir | 74 +++++++++---------- .../rustc.test.ElaborateDrops.before.mir | 44 ++++------- .../rustc.main.ElaborateDrops.before.mir | 10 +-- .../rustc.move_out_by_subslice.mir_map.0.mir | 42 ++--------- .../rustc.move_out_from_end.mir_map.0.mir | 42 ++--------- 13 files changed, 150 insertions(+), 302 deletions(-) diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs index ef74e9f6e194f..705b94dd4d22c 100644 --- a/src/librustc_mir_build/build/expr/as_rvalue.rs +++ b/src/librustc_mir_build/build/expr/as_rvalue.rs @@ -11,6 +11,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an rvalue suitable for use until the end of the current /// scope expression. @@ -121,7 +123,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { value, ) ); - block.and(Rvalue::Use(Operand::Move(Place::from(result)))) + let result_operand = Operand::Move(Place::from(result)); + this.record_operands_moved(slice::from_ref(&result_operand)); + block.and(Rvalue::Use(result_operand)) } ExprKind::Cast { source } => { let source = unpack!(block = this.as_operand(block, scope, source)); @@ -165,6 +169,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) } ExprKind::Tuple { fields } => { @@ -175,6 +180,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } ExprKind::Closure { closure_id, substs, upvars, movability } => { @@ -226,6 +232,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), }; + this.record_operands_moved(&operands); block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index 81092854e8781..75d6a45c34a00 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -10,9 +10,10 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; - use rustc_target::spec::abi::Abi; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. @@ -300,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let field_names = this.hir.all_fields(adt_def, variant_index); - let fields = if let Some(FruInfo { base, field_types }) = base { + let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let base = unpack!(block = this.as_place(block, base)); // MIR does not natively support FRU, so for each @@ -335,6 +336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty, active_field_index, ); + this.record_operands_moved(&fields); this.cfg.push_assign( block, source_info, @@ -393,6 +395,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.local_scope(); let value = unpack!(block = this.as_operand(block, scope, value)); let resume = this.cfg.start_new_block(); + this.record_operands_moved(slice::from_ref(&value)); this.cfg.terminate( block, source_info, diff --git a/src/librustc_mir_build/build/expr/stmt.rs b/src/librustc_mir_build/build/expr/stmt.rs index 49d6ce39ddfa4..58459ef728609 100644 --- a/src/librustc_mir_build/build/expr/stmt.rs +++ b/src/librustc_mir_build/build/expr/stmt.rs @@ -3,6 +3,7 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; use rustc_middle::middle::region; use rustc_middle::mir::*; +use std::slice; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the HAIR `expr`. @@ -46,6 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if this.hir.needs_drop(lhs.ty) { let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); + this.record_operands_moved(slice::from_ref(&rhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); @@ -150,8 +152,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { break; } } - this.block_context - .push(BlockFrame::TailExpr { tail_result_is_ignored: true, span: expr.span }); + this.block_context.push(BlockFrame::TailExpr { + tail_result_is_ignored: true, + span: expr.span, + }); return Some(expr.span); } } diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs index 3514f417623a3..b1e5afef6e371 100644 --- a/src/librustc_mir_build/build/scope.rs +++ b/src/librustc_mir_build/build/scope.rs @@ -84,7 +84,7 @@ that contains only loops and breakable blocks. It tracks where a `break`, use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::hair::{Arm, Expr, ExprRef, LintLevel}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; @@ -122,8 +122,6 @@ struct Scope { /// end of the vector (top of the stack) first. drops: Vec, - moved_locals: Vec, - /// The drop index that will drop everything in and below this scope on an /// unwind path. cached_unwind_block: Option, @@ -411,7 +409,6 @@ impl<'tcx> Scopes<'tcx> { region_scope: region_scope.0, region_scope_span: region_scope.1.span, drops: vec![], - moved_locals: vec![], cached_unwind_block: None, cached_generator_drop_block: None, }); @@ -905,14 +902,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local); } - /// Indicates that the "local operand" stored in `local` is + /// Indicates that the "local operands" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, /// it's an intermediate operand created as part of preparing some /// MIR instruction). We use this information to suppress - /// redundant drops on the non-unwind paths. This results in less - /// MIR, but also avoids spurious borrow check errors - /// (c.f. #64391). + /// redundant drops. This results in less MIR, but also avoids spurious + /// borrow check errors (c.f. #64391). /// /// Example: when compiling the call to `foo` here: /// @@ -948,29 +944,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } - Some(local_scope) => self - .scopes - .scopes - .iter_mut() - .rfind(|scope| scope.region_scope == local_scope) - .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)), + Some(local_scope) => { + let top_scope = self.scopes.scopes.last_mut().unwrap(); + assert!( + top_scope.region_scope == local_scope, + "local scope ({:?}) is not the topmost scope!", + local_scope + ); + + top_scope + } }; // look for moves of a local variable, like `MOVE(_X)` - let locals_moved = operands.iter().flat_map(|operand| match operand { - Operand::Copy(_) | Operand::Constant(_) => None, - Operand::Move(place) => place.as_local(), - }); + let locals_moved = operands + .iter() + .flat_map(|operand| match operand { + Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Move(place) => place.as_local(), + }) + .collect::>(); - for local in locals_moved { - // check if we have a Drop for this operand and -- if so - // -- add it to the list of moved operands. Note that this - // local might not have been an operand created for this - // call, it could come from other places too. - if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) { - scope.moved_locals.push(local); - } - } + // Remove the drops for the moved operands. + scope + .drops + .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local)); + scope.invalidate_cache(); } // Other @@ -1315,14 +1314,6 @@ fn build_scope_drops<'tcx>( debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind); unwind_to = unwind_drops.drops[unwind_to].1; - // If the operand has been moved, and we are not on an unwind - // path, then don't generate the drop. (We only take this into - // account for non-unwind paths so as not to disturb the - // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { - continue; - } - unwind_drops.add_entry(block, unwind_to); let next = cfg.start_new_block(); diff --git a/src/test/mir-opt/basic_assignment/rustc.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment/rustc.main.SimplifyCfg-initial.after.mir index c0a292332711b..19e7eef69fd81 100644 --- a/src/test/mir-opt/basic_assignment/rustc.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment/rustc.main.SimplifyCfg-initial.after.mir @@ -47,14 +47,10 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 - replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 + replace(_5 <- move _6) -> [return: bb1, unwind: bb4]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 } bb1: { - drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb2: { StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 // ty::Const @@ -63,34 +59,30 @@ fn main() -> () { // mir::Constant // + span: $DIR/basic_assignment.rs:10:11: 24:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_5) -> [return: bb2, unwind: bb5]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb3: { + bb2: { StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 - drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_4) -> [return: bb3, unwind: bb6]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb4: { + bb3: { StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2 return; // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2 } - bb5 (cleanup): { - drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb6 (cleanup): { - drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + bb4 (cleanup): { + drop(_5) -> bb5; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb7 (cleanup): { - drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + bb5 (cleanup): { + drop(_4) -> bb6; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2 } } diff --git a/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir index 3263bdd08d45a..64bc8159398aa 100644 --- a/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr/rustc.main.ElaborateDrops.before.mir @@ -14,7 +14,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = const S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + (*_2) = const S::new() -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // ty::Const // + ty: fn() -> S {S::new} // + val: Value(Scalar()) @@ -25,15 +25,11 @@ fn main() -> () { bb1: { _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - } - - bb2: { StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = const std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = const std::mem::drop::>(move _4) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // ty::Const // + ty: fn(std::boxed::Box) {std::mem::drop::>} // + val: Value(Scalar()) @@ -42,7 +38,7 @@ fn main() -> () { // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { + bb2: { StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 @@ -52,27 +48,23 @@ fn main() -> () { // mir::Constant // + span: $DIR/box_expr.rs:6:11: 9:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb3; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb3: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + bb4 (cleanup): { + drop(_1) -> bb6; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + bb5 (cleanup): { + drop(_2) -> bb6; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/issue-41110/rustc.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue-41110/rustc.main.ElaborateDrops.after.mir index 3272ca8454e9c..77549c0b3c675 100644 --- a/src/test/mir-opt/issue-41110/rustc.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue-41110/rustc.main.ElaborateDrops.after.mir @@ -6,33 +6,18 @@ fn main() -> () { let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:8:13: 8:14 let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:27 let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:8:27: 8:28 scope 1 { debug x => _1; // in scope 1 at $DIR/issue-41110.rs:8:9: 8:10 } bb0: { - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 - // ty::Const - // + ty: bool - // + val: Value(Scalar(0x00)) - // mir::Constant - // + span: $DIR/issue-41110.rs:8:9: 8:10 - // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 - _5 = const true; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 - // ty::Const - // + ty: bool - // + val: Value(Scalar(0x01)) - // mir::Constant - // + span: $DIR/issue-41110.rs:8:13: 8:14 - // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } _2 = S; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - _3 = const S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + _3 = const S::id(move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // ty::Const // + ty: fn(S) -> S {S::id} // + val: Value(Scalar()) @@ -43,14 +28,7 @@ fn main() -> () { bb1: { StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 - // ty::Const - // + ty: bool - // + val: Value(Scalar(0x00)) - // mir::Constant - // + span: $DIR/issue-41110.rs:8:13: 8:28 - // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } - _1 = const S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _1 = const S::other(move _2, move _3) -> bb2; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // ty::Const // + ty: fn(S, S) {S::other} // + val: Value(Scalar()) @@ -61,13 +39,6 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - // ty::Const - // + ty: bool - // + val: Value(Scalar(0x00)) - // mir::Constant - // + span: $DIR/issue-41110.rs:8:27: 8:28 - // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 // ty::Const @@ -81,26 +52,10 @@ fn main() -> () { } bb3 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + drop(_2) -> bb4; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb4 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - } - - bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb6 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:7:1: 9:2 } - - bb7 (cleanup): { - drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb8 (cleanup): { - switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } } diff --git a/src/test/mir-opt/issue-41110/rustc.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue-41110/rustc.test.ElaborateDrops.after.mir index 99da0398d9639..870428c7e3da7 100644 --- a/src/test/mir-opt/issue-41110/rustc.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue-41110/rustc.test.ElaborateDrops.after.mir @@ -37,7 +37,7 @@ fn test() -> () { StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 - _3 = const std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 + _3 = const std::mem::drop::(move _4) -> [return: bb1, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // ty::Const // + ty: fn(S) {std::mem::drop::} // + val: Value(Scalar()) @@ -58,14 +58,10 @@ fn test() -> () { // + span: $DIR/issue-41110.rs:18:9: 18:10 // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } _5 = move _1; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - goto -> bb12; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb9; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb2: { - goto -> bb3; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb3: { StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 // ty::Const @@ -74,15 +70,15 @@ fn test() -> () { // mir::Constant // + span: $DIR/issue-41110.rs:14:15: 19:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + drop(_2) -> [return: bb3, unwind: bb6]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb4: { + bb3: { StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb4; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb5: { + bb4: { _6 = const false; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 // ty::Const // + ty: bool @@ -94,41 +90,33 @@ fn test() -> () { return; // scope 0 at $DIR/issue-41110.rs:19:2: 19:2 } - bb6 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb7 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 - } - - bb8 (cleanup): { - goto -> bb9; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + bb5 (cleanup): { + goto -> bb6; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb9 (cleanup): { - goto -> bb14; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb6 (cleanup): { + goto -> bb11; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb10 (cleanup): { + bb7 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 } - bb11 (cleanup): { + bb8 (cleanup): { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 - goto -> bb6; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb12: { + bb9: { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 goto -> bb2; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb13 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb10 (cleanup): { + drop(_1) -> bb7; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb14 (cleanup): { - switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb11 (cleanup): { + switchInt(_6) -> [false: bb7, otherwise: bb10]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } } diff --git a/src/test/mir-opt/issue-41888/rustc.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue-41888/rustc.main.ElaborateDrops.after.mir index b64dd5c3776cf..b7cf4ace4ba4f 100644 --- a/src/test/mir-opt/issue-41888/rustc.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue-41888/rustc.main.ElaborateDrops.after.mir @@ -44,7 +44,7 @@ fn main() -> () { // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - _2 = const cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 + _2 = const cond() -> [return: bb1, unwind: bb9]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // ty::Const // + ty: fn() -> bool {cond} // + val: Value(Scalar()) @@ -65,7 +65,7 @@ fn main() -> () { // mir::Constant // + span: $DIR/issue-41888.rs:8:5: 14:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } bb3: { @@ -74,20 +74,16 @@ fn main() -> () { _4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb12; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb4: { - goto -> bb5; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb5: { StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 _5 = discriminant(_1); // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 - switchInt(move _5) -> [0isize: bb7, otherwise: bb6]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 + switchInt(move _5) -> [0isize: bb6, otherwise: bb5]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 } - bb6: { + bb5: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 // ty::Const // + ty: () @@ -95,10 +91,10 @@ fn main() -> () { // mir::Constant // + span: $DIR/issue-41888.rs:10:9: 13:10 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb7: { + bb6: { StorageLive(_6); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 // ty::Const @@ -116,14 +112,14 @@ fn main() -> () { // + span: $DIR/issue-41888.rs:10:29: 13:10 // + literal: Const { ty: (), val: Value(Scalar()) } StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb8: { - goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb7: { + goto -> bb18; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb9: { + bb8: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 // ty::Const // + ty: bool @@ -150,19 +146,15 @@ fn main() -> () { return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2 } - bb10 (cleanup): { - goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb11 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb9 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb12 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2 } - bb13 (cleanup): { + bb11 (cleanup): { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 // ty::Const // + ty: bool @@ -185,10 +177,10 @@ fn main() -> () { // + span: $DIR/issue-41888.rs:9:9: 9:10 // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 - goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb9; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb14: { + bb12: { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 // ty::Const // + ty: bool @@ -214,7 +206,7 @@ fn main() -> () { goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb15: { + bb13: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 // ty::Const // + ty: bool @@ -222,36 +214,36 @@ fn main() -> () { // mir::Constant // + span: $DIR/issue-41888.rs:15:1: 15:2 // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } - goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + goto -> bb8; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb16 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb14 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb17: { - drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb15: { + drop(_1) -> [return: bb13, unwind: bb10]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb18 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb16 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb19: { + bb17: { _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _10) -> [0isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _10) -> [0isize: bb13, otherwise: bb15]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb20: { - switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb18: { + switchInt(_7) -> [false: bb13, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb21 (cleanup): { + bb19 (cleanup): { _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _11) -> [0isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _11) -> [0isize: bb14, otherwise: bb16]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb22 (cleanup): { - switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb20 (cleanup): { + switchInt(_7) -> [false: bb10, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } } diff --git a/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir index dc395cbeb4f45..662ecfa583e17 100644 --- a/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> std::option::Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = std::option::Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = const as std::ops::Try>::into_result(move _4) -> [return: bb1, unwind: bb13]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = const as std::ops::Try>::into_result(move _4) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // ty::Const // + ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result} // + val: Value(Scalar()) @@ -51,7 +51,11 @@ fn test() -> std::option::Option> { (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = std::option::Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb3: { @@ -64,7 +68,7 @@ fn test() -> std::option::Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = const >::from(move _9) -> [return: bb5, unwind: bb13]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = const >::from(move _9) -> [return: bb5, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // ty::Const // + ty: fn(std::option::NoneError) -> std::option::NoneError {>::from} // + val: Value(Scalar()) @@ -75,7 +79,7 @@ fn test() -> std::option::Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb6, unwind: bb13]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb6, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // ty::Const // + ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error} // + val: Value(Scalar()) @@ -87,45 +91,29 @@ fn test() -> std::option::Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> [return: bb9, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb7, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = std::option::Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> [return: bb8, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - } - - bb8: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 - } - - bb9: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10: { + bb8: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb11 (cleanup): { - drop(_0) -> bb14; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - } - - bb12 (cleanup): { - drop(_1) -> bb14; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb9 (cleanup): { + drop(_0) -> bb11; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 } - bb13 (cleanup): { - drop(_2) -> bb14; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb10 (cleanup): { + drop(_2) -> bb11; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb14 (cleanup): { + bb11 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/no-spurious-drop-after-call/rustc.main.ElaborateDrops.before.mir b/src/test/mir-opt/no-spurious-drop-after-call/rustc.main.ElaborateDrops.before.mir index 0d619af101a18..79bbba481005b 100644 --- a/src/test/mir-opt/no-spurious-drop-after-call/rustc.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no-spurious-drop-after-call/rustc.main.ElaborateDrops.before.mir @@ -31,7 +31,7 @@ fn main() -> () { bb1: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = const std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = const std::mem::drop::(move _2) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // ty::Const // + ty: fn(std::string::String) {std::mem::drop::} // + val: Value(Scalar()) @@ -53,12 +53,4 @@ fn main() -> () { // + literal: Const { ty: (), val: Value(Scalar()) } return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } - - bb3 (cleanup): { - drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 - } - - bb4 (cleanup): { - resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2 - } } diff --git a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir index 33c2cb78bd82e..4d0bc8dd48c4b 100644 --- a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir @@ -28,10 +28,6 @@ fn move_out_by_subslice() -> () { // + span: $DIR/uniform_array_move_out.rs:11:18: 11:19 // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 @@ -44,21 +40,9 @@ fn move_out_by_subslice() -> () { // + span: $DIR/uniform_array_move_out.rs:11:25: 11:26 // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 @@ -70,36 +54,24 @@ fn move_out_by_subslice() -> () { // mir::Constant // + span: $DIR/uniform_array_move_out.rs:10:27: 13:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_6) -> [return: bb5, unwind: bb8]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb8 (cleanup): { - drop(_1) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - } - - bb9 (cleanup): { - drop(_4) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb10 (cleanup): { - drop(_2) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb11 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir index 9d4b5b57fc479..a34bb007be3e1 100644 --- a/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir @@ -28,10 +28,6 @@ fn move_out_from_end() -> () { // + span: $DIR/uniform_array_move_out.rs:5:18: 5:19 // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 @@ -44,21 +40,9 @@ fn move_out_from_end() -> () { // + span: $DIR/uniform_array_move_out.rs:5:25: 5:26 // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 @@ -70,36 +54,24 @@ fn move_out_from_end() -> () { // mir::Constant // + span: $DIR/uniform_array_move_out.rs:4:24: 7:2 // + literal: Const { ty: (), val: Value(Scalar()) } - drop(_6) -> [return: bb5, unwind: bb8]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb8 (cleanup): { - drop(_1) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - } - - bb9 (cleanup): { - drop(_4) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb10 (cleanup): { - drop(_2) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb11 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } }