From af8c2339cfb26363610899e6bffbd1913e83db08 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 28 Nov 2017 01:43:59 +0200 Subject: [PATCH 1/7] fix handling of borrows at a function's end --- src/librustc_mir/borrow_check.rs | 102 +++++++++++++++------ src/librustc_mir/dataflow/impls/borrows.rs | 4 + 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 63b4175ce44..ee48d1d369d 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -384,33 +384,23 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let domain = flow_state.borrows.base_results.operator(); - for borrow in domain.borrows() { - let root_place = self.prefixes( - &borrow.place, - PrefixSet::All - ).last().unwrap(); - match root_place { - Place::Static(_) => { - self.access_place( - ContextKind::StorageDead.new(loc), - (&root_place, self.mir.source_info(borrow.location).span), - (Deep, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state - ); - } - Place::Local(_) => { - self.access_place( - ContextKind::StorageDead.new(loc), - (&root_place, self.mir.source_info(borrow.location).span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state - ); - } - Place::Projection(_) => () + let data = domain.borrows(); + flow_state.borrows.with_elems_outgoing(|borrows| for i in borrows { + let borrow = &data[i]; + + if self.place_is_invalidated_at_exit(&borrow.place) { + debug!("borrow conflicts at exit {:?}", borrow); + let borrow_span = self.mir.source_info(borrow.location).span; + // FIXME: should be talking about the region lifetime instead + // of just a span here. + let end_span = domain.opt_region_end_span(&borrow.region); + + self.report_borrowed_value_does_not_live_long_enough( + ContextKind::StorageDead.new(loc), + (&borrow.place, borrow_span), + end_span) } - } + }); } TerminatorKind::Goto { target: _ } | TerminatorKind::Unreachable | @@ -594,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context, common_prefix, place_span, bk, &borrow, end_issued_loan_span) } - WriteKind::StorageDeadOrDrop => { + WriteKind::StorageDeadOrDrop => { let end_span = flow_state.borrows.base_results.operator().opt_region_end_span( &borrow.region); @@ -751,6 +741,50 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Operand::Constant(_) => {} } } + + /// Returns whether a borrow of this place is invalidated when the function + /// exits + fn place_is_invalidated_at_exit(&self, place: &Place<'tcx>) -> bool { + debug!("place_is_invalidated_at_exit({:?})", place); + let root_place = self.prefixes(place, PrefixSet::All).last().unwrap(); + + // FIXME(nll-rfc#40): do more precise destructor tracking here. For now + // we just know that all locals are dropped at function exit (otherwise + // we'll have a memory leak) and assume that all statics have a destructor. + let (might_be_alive, will_be_dropped) = match root_place { + Place::Static(statik) => { + // Thread-locals might be dropped after the function exits, but + // "true" statics will never be. + let is_thread_local = self.tcx.get_attrs(statik.def_id).iter().any(|attr| { + attr.check_name("thread_local") + }); + + (true, is_thread_local) + } + Place::Local(_) => { + // Locals are always dropped at function exit, and if they + // have a destructor it would've been called already. + (false, true) + } + Place::Projection(..) => bug!("root of {:?} is a projection ({:?})?", + place, root_place) + }; + + if !will_be_dropped { + debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); + return false; + } + + // FIXME: replace this with a proper borrow_conflicts_with_place when + // that is merged. + let prefix_set = if might_be_alive { + PrefixSet::Supporting + } else { + PrefixSet::Shallow + }; + + self.prefixes(place, prefix_set).any(|prefix| prefix == root_place) + } } impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { @@ -1667,13 +1701,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn report_borrowed_value_does_not_live_long_enough(&mut self, _: Context, - (place, span): (&Place, Span), + (place, span): (&Place<'tcx>, Span), end_span: Option) { - let proper_span = match *place { + let root_place = self.prefixes(place, PrefixSet::All).last().unwrap(); + let proper_span = match *root_place { Place::Local(local) => self.mir.local_decls[local].source_info.span, _ => span }; - let mut err = self.tcx.path_does_not_live_long_enough(span, "borrowed value", Origin::Mir); err.span_label(proper_span, "temporary value created here"); err.span_label(span, "temporary value dropped here while still borrowed"); @@ -2162,4 +2196,12 @@ impl FlowInProgress where BD: BitDenotation { let univ = self.base_results.sets().bits_per_block(); self.curr_state.elems(univ) } + + fn with_elems_outgoing(&self, f: F) where F: FnOnce(indexed_set::Elems) { + let mut curr_state = self.curr_state.clone(); + curr_state.union(&self.stmt_gen); + curr_state.subtract(&self.stmt_kill); + let univ = self.base_results.sets().bits_per_block(); + f(curr_state.elems(univ)); + } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 32dcf28cd94..c87e91b5e63 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -132,6 +132,10 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { &self.borrows[idx].location } + pub fn nonlexical_regioncx(&self) -> Option<&'a RegionInferenceContext<'tcx>> { + self.nonlexical_regioncx + } + /// Returns the span for the "end point" given region. This will /// return `None` if NLL is enabled, since that concept has no /// meaning there. Otherwise, return region span if it exists and From a6e24fc31f4b4bb803e10a39902107f86916133a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Nov 2017 17:58:59 +0200 Subject: [PATCH 2/7] initialize the destination in unit statements Fixes #46159. --- src/librustc_mir/build/expr/into.rs | 4 +++- src/test/mir-opt/validate_4.rs | 1 + src/test/run-pass/weird-exprs.rs | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 0cdac04b810..1d724d7b4e6 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -273,7 +273,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Break { .. } | ExprKind::InlineAsm { .. } | ExprKind::Return {.. } => { - this.stmt_expr(block, expr) + unpack!(block = this.stmt_expr(block, expr)); + this.cfg.push_assign_unit(block, source_info, destination); + block.unit() } // these are the cases that are more naturally handled by some other mode diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs index fb0c8871d83..24a4ebd8429 100644 --- a/src/test/mir-opt/validate_4.rs +++ b/src/test/mir-opt/validate_4.rs @@ -54,6 +54,7 @@ fn main() { // Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]); // Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]); // (*_2) = const 23i32; +// _0 = (); // return; // } // } diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index 64fd9e0a772..ecb62b1888d 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z borrowck=compare use std::cell::Cell; use std::mem::swap; From 25416c70814eb64a8cdd709af7aba1833832bebf Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Nov 2017 18:13:40 +0200 Subject: [PATCH 3/7] don't track borrows for empty regions Region inference can create borrows for an empty region if the borrow is dead. In that case, there's no reason to track the borrow, but because there's no such thing as an EndRegion(ReEmpty) these borrows used to live for the entire function. Fixes #46161. --- src/librustc_mir/dataflow/impls/borrows.rs | 6 ++++++ src/test/run-pass/issue-8860.rs | 1 + 2 files changed, 7 insertions(+) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index c87e91b5e63..19ab45dda95 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -212,6 +212,12 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::Assign(_, ref rhs) => { if let mir::Rvalue::Ref(region, _, ref place) = *rhs { if is_unsafe_place(self.tcx, self.mir, place) { return; } + if let RegionKind::ReEmpty = region { + // If the borrowed value is dead, the region for it + // can be empty. Don't track the borrow in that case. + return + } + let index = self.location_map.get(&location).unwrap_or_else(|| { panic!("could not find BorrowIndex for location {:?}", location); }); diff --git a/src/test/run-pass/issue-8860.rs b/src/test/run-pass/issue-8860.rs index ff562aac161..127f9e355c7 100644 --- a/src/test/run-pass/issue-8860.rs +++ b/src/test/run-pass/issue-8860.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z borrowck=compare static mut DROP: isize = 0; static mut DROP_S: isize = 0; From 485476c25a666ee89210c8ff9035836dc678547a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Nov 2017 21:50:36 +0200 Subject: [PATCH 4/7] add a pass to remove no-op landing pads --- src/librustc/mir/mod.rs | 25 ++++ src/librustc_mir/transform/mod.rs | 5 + src/librustc_mir/transform/no_landing_pads.rs | 19 +-- .../transform/remove_noop_landing_pads.rs | 137 ++++++++++++++++++ 4 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 src/librustc_mir/transform/remove_noop_landing_pads.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0cbd945095a..cd4ed8081c3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -733,6 +733,10 @@ impl<'tcx> Terminator<'tcx> { pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { self.kind.successors_mut() } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + self.kind.unwind_mut() + } } impl<'tcx> TerminatorKind<'tcx> { @@ -811,6 +815,27 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + match *self { + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::Return | + TerminatorKind::Unreachable | + TerminatorKind::GeneratorDrop | + TerminatorKind::Yield { .. } | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::FalseEdges { .. } => { + None + }, + TerminatorKind::Call { cleanup: ref mut unwind, .. } | + TerminatorKind::Assert { cleanup: ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut unwind, .. } | + TerminatorKind::Drop { ref mut unwind, .. } => { + Some(unwind) + } + } + } } impl<'tcx> BasicBlockData<'tcx> { diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 418d3d22058..64ba5ae3e8b 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -36,6 +36,7 @@ pub mod elaborate_drops; pub mod add_call_guards; pub mod promote_consts; pub mod qualify_consts; +pub mod remove_noop_landing_pads; pub mod dump_mir; pub mod deaggregator; pub mod instcombine; @@ -226,8 +227,11 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx let mut mir = tcx.mir_validated(def_id).steal(); run_passes![tcx, mir, def_id, 2; + // Remove all things not needed by analysis no_landing_pads::NoLandingPads, simplify_branches::SimplifyBranches::new("initial"), + remove_noop_landing_pads::RemoveNoopLandingPads, + simplify::SimplifyCfg::new("early-opt"), // These next passes must be executed together add_call_guards::CriticalCallEdges, @@ -255,6 +259,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx instcombine::InstCombine, deaggregator::Deaggregator, copy_prop::CopyPropagation, + remove_noop_landing_pads::RemoveNoopLandingPads, simplify::SimplifyLocals, generator::StateTransform, diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index dd5898cb561..c8f171d4160 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -38,23 +38,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { bb: BasicBlock, terminator: &mut Terminator<'tcx>, location: Location) { - match terminator.kind { - TerminatorKind::Goto { .. } | - TerminatorKind::Resume | - TerminatorKind::Return | - TerminatorKind::Unreachable | - TerminatorKind::GeneratorDrop | - TerminatorKind::Yield { .. } | - TerminatorKind::SwitchInt { .. } | - TerminatorKind::FalseEdges { .. } => { - /* nothing to do */ - }, - TerminatorKind::Call { cleanup: ref mut unwind, .. } | - TerminatorKind::Assert { cleanup: ref mut unwind, .. } | - TerminatorKind::DropAndReplace { ref mut unwind, .. } | - TerminatorKind::Drop { ref mut unwind, .. } => { - unwind.take(); - }, + if let Some(unwind) = terminator.kind.unwind_mut() { + unwind.take(); } self.super_terminator(bb, terminator, location); } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs new file mode 100644 index 00000000000..d29174d5719 --- /dev/null +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -0,0 +1,137 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use rustc::mir::*; +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::Idx; +use transform::{MirPass, MirSource}; +use util::patch::MirPatch; + +/// A pass that removes no-op landing pads and replaces jumps to them with +/// `None`. This is important because otherwise LLVM generates terrible +/// code for these. +pub struct RemoveNoopLandingPads; + +impl MirPass for RemoveNoopLandingPads { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _src: MirSource, + mir: &mut Mir<'tcx>) { + if tcx.sess.no_landing_pads() { + return + } + + debug!("remove_noop_landing_pads({:?})", mir); + self.remove_nop_landing_pads(mir); + } +} + +impl RemoveNoopLandingPads { + fn is_nop_landing_pad(&self, bb: BasicBlock, mir: &Mir, nop_landing_pads: &BitVector) + -> bool + { + for stmt in &mir[bb].statements { + match stmt.kind { + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) | + StatementKind::EndRegion(_) | + StatementKind::Nop => { + // These are all nops in a landing pad (there's some + // borrowck interaction between EndRegion and storage + // instructions, but this should all run after borrowck). + } + + StatementKind::Assign(Place::Local(_), Rvalue::Use(_)) => { + // Writing to a local (e.g. a drop flag) does not + // turn a landing pad to a non-nop + } + + StatementKind::Assign(_, _) | + StatementKind::SetDiscriminant { .. } | + StatementKind::InlineAsm { .. } | + StatementKind::Validate { .. } => { + return false; + } + } + } + + let terminator = mir[bb].terminator(); + match terminator.kind { + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::FalseEdges { .. } => { + terminator.successors().iter().all(|succ| { + nop_landing_pads.contains(succ.index()) + }) + }, + TerminatorKind::GeneratorDrop | + TerminatorKind::Yield { .. } | + TerminatorKind::Return | + TerminatorKind::Unreachable | + TerminatorKind::Call { .. } | + TerminatorKind::Assert { .. } | + TerminatorKind::DropAndReplace { .. } | + TerminatorKind::Drop { .. } => { + false + } + } + } + + fn remove_nop_landing_pads(&self, mir: &mut Mir) { + // make sure there's a single resume block + let resume_block = { + let patch = MirPatch::new(mir); + let resume_block = patch.resume_block(); + patch.apply(mir); + resume_block + }; + debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); + + let mut jumps_folded = 0; + let mut landing_pads_removed = 0; + let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len()); + + // This is a post-order traversal, so that if A post-dominates B + // then A will be visited before B. + let postorder: Vec<_> = traversal::postorder(mir).map(|(bb, _)| bb).collect(); + for bb in postorder { + debug!(" processing {:?}", bb); + for target in mir[bb].terminator_mut().successors_mut() { + if *target != resume_block && nop_landing_pads.contains(target.index()) { + debug!(" folding noop jump to {:?} to resume block", target); + *target = resume_block; + jumps_folded += 1; + } + } + + match mir[bb].terminator_mut().unwind_mut() { + Some(unwind) => { + if *unwind == Some(resume_block) { + debug!(" removing noop landing pad"); + jumps_folded -= 1; + landing_pads_removed += 1; + *unwind = None; + } + } + _ => {} + } + + let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads); + if is_nop_landing_pad { + nop_landing_pads.insert(bb.index()); + } + debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); + } + + debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); + } +} From 9dc396747b31a7c3918d44bd30be115360712f9f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 28 Nov 2017 01:45:16 +0200 Subject: [PATCH 5/7] funnel all unwind paths through a single Resume block This simplifies analysis and borrow-checking because liveness at the resume point can always be simply propagated. Later on, the "dead" Resumes are removed. --- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/scope.rs | 65 +++--- src/librustc_mir/transform/mod.rs | 1 + src/librustc_mir/transform/simplify.rs | 34 --- src/test/mir-opt/basic_assignment.rs | 12 +- src/test/mir-opt/box_expr.rs | 14 +- src/test/mir-opt/end_region_4.rs | 12 +- src/test/mir-opt/end_region_5.rs | 12 +- src/test/mir-opt/end_region_6.rs | 12 +- src/test/mir-opt/end_region_7.rs | 7 +- src/test/mir-opt/end_region_8.rs | 12 +- src/test/mir-opt/end_region_cyclic.rs | 24 +- .../end_region_destruction_extents_1.rs | 12 +- src/test/mir-opt/match_false_edges.rs | 211 +++++++++--------- .../mir-opt/nll/liveness-call-subtlety.rs | 12 +- .../mir-opt/nll/liveness-drop-intra-block.rs | 16 +- src/test/mir-opt/nll/liveness-interblock.rs | 22 +- src/test/mir-opt/nll/region-liveness-basic.rs | 22 +- .../nll/region-liveness-drop-may-dangle.rs | 2 +- .../nll/region-liveness-two-disjoint-uses.rs | 6 +- .../mir-opt/nll/region-subtyping-basic.rs | 6 +- .../mir-opt/packed-struct-drop-aligned.rs | 2 +- src/test/mir-opt/simplify_if.rs | 4 +- src/test/mir-opt/validate_2.rs | 2 +- 25 files changed, 263 insertions(+), 263 deletions(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 1d724d7b4e6..ed339110537 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(block, source_info, TerminatorKind::Call { func: fun, args, - cleanup, + cleanup: Some(cleanup), destination: if diverges { None } else { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 7c9f190670b..b2357b77157 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -315,7 +315,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }), args: vec![val, expect], destination: Some((eq_result.clone(), eq_block)), - cleanup, + cleanup: Some(cleanup), }); // check the result diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 3814dde17bb..630d0bf1792 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -383,7 +383,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert_eq!(scope.region_scope, region_scope.0); self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope); + let resume_block = self.resume_block(); unpack!(block = build_scope_drops(&mut self.cfg, + resume_block, &scope, &self.scopes, block, @@ -422,6 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } { + let resume_block = self.resume_block(); let mut rest = &mut self.scopes[(len - scope_count)..]; while let Some((scope, rest_)) = {rest}.split_last_mut() { rest = rest_; @@ -441,6 +444,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope); unpack!(block = build_scope_drops(&mut self.cfg, + resume_block, scope, rest, block, @@ -468,6 +472,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let src_info = self.scopes[0].source_info(self.fn_span); let mut block = self.cfg.start_new_block(); let result = block; + let resume_block = self.resume_block(); let mut rest = &mut self.scopes[..]; while let Some((scope, rest_)) = {rest}.split_last_mut() { @@ -491,6 +496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope); unpack!(block = build_scope_drops(&mut self.cfg, + resume_block, scope, rest, block, @@ -701,18 +707,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// This path terminates in Resume. Returns the start of the path. /// See module comment for more details. None indicates there’s no /// cleanup to do at this point. - pub fn diverge_cleanup(&mut self) -> Option { + pub fn diverge_cleanup(&mut self) -> BasicBlock { self.diverge_cleanup_gen(false) } - fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> Option { - if !self.scopes.iter().any(|scope| scope.needs_cleanup) { - return None; + fn resume_block(&mut self) -> BasicBlock { + if let Some(target) = self.cached_resume_block { + target + } else { + let resumeblk = self.cfg.start_new_cleanup_block(); + self.cfg.terminate(resumeblk, + SourceInfo { + scope: ARGUMENT_VISIBILITY_SCOPE, + span: self.fn_span + }, + TerminatorKind::Resume); + self.cached_resume_block = Some(resumeblk); + resumeblk } - assert!(!self.scopes.is_empty()); // or `any` above would be false + } - let Builder { ref mut cfg, ref mut scopes, - ref mut cached_resume_block, .. } = *self; + fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock { + // To start, create the resume terminator. + let mut target = self.resume_block(); + + let Builder { ref mut cfg, ref mut scopes, .. } = *self; // Build up the drops in **reverse** order. The end result will // look like: @@ -725,23 +744,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // store caches. If everything is cached, we'll just walk right // to left reading the cached results but never created anything. - // To start, create the resume terminator. - let mut target = if let Some(target) = *cached_resume_block { - target - } else { - let resumeblk = cfg.start_new_cleanup_block(); - cfg.terminate(resumeblk, - scopes[0].source_info(self.fn_span), - TerminatorKind::Resume); - *cached_resume_block = Some(resumeblk); - resumeblk - }; - - for scope in scopes.iter_mut() { - target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span, - scope, target, generator_drop); + if scopes.iter().any(|scope| scope.needs_cleanup) { + for scope in scopes.iter_mut() { + target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span, + scope, target, generator_drop); + } } - Some(target) + + target } /// Utility function for *non*-scope code to build their own drops @@ -760,7 +770,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::Drop { location, target: next_target, - unwind: diverge_target, + unwind: Some(diverge_target), }); next_target.unit() } @@ -779,7 +789,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { location, value, target: next_target, - unwind: diverge_target, + unwind: Some(diverge_target), }); next_target.unit() } @@ -804,7 +814,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { expected, msg, target: success_block, - cleanup, + cleanup: Some(cleanup), }); success_block @@ -813,6 +823,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Builds drops for pop_scope and exit_scope. fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, + resume_block: BasicBlock, scope: &Scope<'tcx>, earlier_scopes: &[Scope<'tcx>], mut block: BasicBlock, @@ -868,7 +879,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, cfg.terminate(block, source_info, TerminatorKind::Drop { location: drop_data.location.clone(), target: next, - unwind: on_diverge + unwind: Some(on_diverge.unwrap_or(resume_block)) }); block = next; } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 64ba5ae3e8b..830838c6037 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -260,6 +260,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx deaggregator::Deaggregator, copy_prop::CopyPropagation, remove_noop_landing_pads::RemoveNoopLandingPads, + simplify::SimplifyCfg::new("final"), simplify::SimplifyLocals, generator::StateTransform, diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 2e7c3714ffe..e7675b4ceaf 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -124,8 +124,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { self.collapse_goto_chain(successor, &mut changed); } - changed |= self.simplify_unwind(&mut terminator); - let mut new_stmts = vec![]; let mut inner_changed = true; while inner_changed { @@ -238,38 +236,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { true } - // turn an unwind branch to a resume block into a None - fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool { - let unwind = match terminator.kind { - TerminatorKind::Drop { ref mut unwind, .. } | - TerminatorKind::DropAndReplace { ref mut unwind, .. } | - TerminatorKind::Call { cleanup: ref mut unwind, .. } | - TerminatorKind::Assert { cleanup: ref mut unwind, .. } => - unwind, - _ => return false - }; - - if let &mut Some(unwind_block) = unwind { - let is_resume_block = match self.basic_blocks[unwind_block] { - BasicBlockData { - ref statements, - terminator: Some(Terminator { - kind: TerminatorKind::Resume, .. - }), .. - } if statements.is_empty() => true, - _ => false - }; - if is_resume_block { - debug!("simplifying unwind to {:?} from {:?}", - unwind_block, terminator.source_info); - *unwind = None; - } - return is_resume_block; - } - - false - } - fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index a8b87a273bf..321c05c4903 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -50,16 +50,16 @@ fn main() { // StorageLive(_5); // StorageLive(_6); // _6 = move _4; -// replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; +// replace(_5 <-move _6) -> [return: bb2, unwind: bb5]; // } // bb1: { -// drop(_6) -> [return: bb6, unwind: bb4]; -// } -// bb2: { // resume; // } +// bb2: { +// drop(_6) -> [return: bb6, unwind: bb4]; +// } // bb3: { -// drop(_4) -> bb2; +// drop(_4) -> bb1; // } // bb4: { // drop(_5) -> bb3; @@ -74,7 +74,7 @@ fn main() { // } // bb7: { // StorageDead(_5); -// drop(_4) -> bb8; +// drop(_4) -> [return: bb8, unwind: bb1]; // } // bb8: { // StorageDead(_4); diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index 74e07d5e864..ed9c303a16f 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -44,20 +44,20 @@ impl Drop for S { // StorageLive(_1); // StorageLive(_2); // _2 = Box(S); -// (*_2) = const S::new() -> [return: bb1, unwind: bb3]; +// (*_2) = const S::new() -> [return: bb2, unwind: bb3]; // } // // bb1: { +// resume; +// } +// +// bb2: { // _1 = move _2; // drop(_2) -> bb4; // } // -// bb2: { -// resume; -// } -// // bb3: { -// drop(_2) -> bb2; +// drop(_2) -> bb1; // } // // bb4: { @@ -72,7 +72,7 @@ impl Drop for S { // } // // bb6: { -// drop(_1) -> bb2; +// drop(_1) -> bb1; // } // // bb7: { diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs index d9456ef1563..ded818688d7 100644 --- a/src/test/mir-opt/end_region_4.rs +++ b/src/test/mir-opt/end_region_4.rs @@ -51,9 +51,12 @@ fn foo(i: i32) { // _3 = &'26_2rs _2; // StorageLive(_5); // _5 = (*_3); -// _4 = const foo(move _5) -> [return: bb1, unwind: bb3]; +// _4 = const foo(move _5) -> [return: bb2, unwind: bb3]; // } // bb1: { +// resume; +// } +// bb2: { // StorageDead(_5); // StorageLive(_6); // _6 = &'26_4rs _2; @@ -63,14 +66,11 @@ fn foo(i: i32) { // EndRegion('26_2rs); // StorageDead(_3); // StorageDead(_2); -// drop(_1) -> bb4; -// } -// bb2: { -// resume; +// drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { // EndRegion('26_2rs); -// drop(_1) -> bb2; +// drop(_1) -> bb1; // } // bb4: { // StorageDead(_1); diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs index c2ee2d62b98..1da97a997a1 100644 --- a/src/test/mir-opt/end_region_5.rs +++ b/src/test/mir-opt/end_region_5.rs @@ -43,20 +43,20 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _4 = &'14s _1; // _3 = [closure@NodeId(18)] { d: move _4 }; // StorageDead(_4); -// _2 = const foo(move _3) -> [return: bb1, unwind: bb3]; +// _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; // } // bb1: { +// resume; +// } +// bb2: { // EndRegion('14s); // StorageDead(_3); // _0 = (); -// drop(_1) -> bb4; -// } -// bb2: { -// resume; +// drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { // EndRegion('14s); -// drop(_1) -> bb2; +// drop(_1) -> bb1; // } // bb4: { // StorageDead(_1); diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index 34675e8842f..dadc755eb8c 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -43,20 +43,20 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _4 = &'19s _1; // _3 = [closure@NodeId(22)] { d: move _4 }; // StorageDead(_4); -// _2 = const foo(move _3) -> [return: bb1, unwind: bb3]; +// _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; // } // bb1: { +// resume; +// } +// bb2: { // EndRegion('19s); // StorageDead(_3); // _0 = (); -// drop(_1) -> bb4; -// } -// bb2: { -// resume; +// drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { // EndRegion('19s); -// drop(_1) -> bb2; +// drop(_1) -> bb1; // } // bb4: { // StorageDead(_1); diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index a9b6d2196fc..1426174b482 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -63,7 +63,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // bb6: { // StorageDead(_3); // _0 = (); -// drop(_1) -> bb7; +// drop(_1) -> [return: bb7, unwind: bb1]; // } // bb7: { // StorageDead(_1); @@ -88,9 +88,12 @@ fn foo(f: F) where F: FnOnce() -> i32 { // StorageDead(_3); // EndRegion('15_0rs); // StorageDead(_2); -// drop(_1) -> bb1; +// drop(_1) -> [return: bb2, unwind: bb1]; // } // bb1: { +// resume; +// } +// bb2: { // return; // } // } diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 4c1ec4b1026..405864aba94 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -48,21 +48,21 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _5 = _2; // _4 = [closure@NodeId(22)] { r: move _5 }; // StorageDead(_5); -// _3 = const foo(move _4) -> [return: bb1, unwind: bb3]; +// _3 = const foo(move _4) -> [return: bb2, unwind: bb3]; // } // bb1: { +// resume; +// } +// bb2: { // StorageDead(_4); // _0 = (); // EndRegion('21_1rs); // StorageDead(_2); -// drop(_1) -> bb4; -// } -// bb2: { -// resume; +// drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { // EndRegion('21_1rs); -// drop(_1) -> bb2; +// drop(_1) -> bb1; // } // bb4: { // StorageDead(_1); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index b8dabada18e..37a6229feba 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -62,6 +62,7 @@ fn query() -> bool { true } // let mut _15: std::option::Option<&'35_0rs S<'35_0rs>>; // let mut _16: &'35_0rs S<'35_0rs>; // let mut _17: &'35_0rs S<'35_0rs>; +// // bb0: { // goto -> bb1; // } @@ -70,9 +71,12 @@ fn query() -> bool { true } // StorageLive(_3); // StorageLive(_4); // _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None; -// _3 = const >::new(move _4) -> bb2; +// _3 = const >::new(move _4) -> [return: bb3, unwind: bb2]; // } // bb2: { +// resume; +// } +// bb3: { // StorageDead(_4); // _2 = S<'35_0rs> { r: move _3 }; // StorageDead(_3); @@ -85,27 +89,27 @@ fn query() -> bool { true } // _8 = &'35_0rs (*_9); // _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,); // StorageDead(_8); -// _5 = const >::set(move _6, move _7) -> bb3; +// _5 = const >::set(move _6, move _7) -> [return: bb4, unwind: bb2]; // } -// bb3: { +// bb4: { // EndRegion('16s); // StorageDead(_7); // StorageDead(_6); // StorageDead(_9); // StorageLive(_11); -// _11 = const query() -> bb4; -// } -// bb4: { -// switchInt(move _11) -> [0u8: bb6, otherwise: bb5]; +// _11 = const query() -> [return: bb5, unwind: bb2]; // } // bb5: { +// switchInt(move _11) -> [0u8: bb7, otherwise: bb6]; +// } +// bb6: { // _0 = (); // StorageDead(_11); // EndRegion('35_0rs); // StorageDead(_2); // return; // } -// bb6: { +// bb7: { // _10 = (); // StorageDead(_11); // StorageLive(_14); @@ -117,9 +121,9 @@ fn query() -> bool { true } // _16 = &'35_0rs (*_17); // _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,); // StorageDead(_16); -// _13 = const >::set(move _14, move_15) -> bb7; +// _13 = const >::set(move _14, move _15) -> [return: bb8, unwind: bb2]; // } -// bb7: { +// bb8: { // EndRegion('33s); // StorageDead(_15); // StorageDead(_14); diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index aebe0a1ff6a..69c5cdccf49 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -99,10 +99,14 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // _2 = (_3.0: &'12ds S1); // _1 = move _2; // StorageDead(_2); -// drop(_3) -> bb1; +// drop(_3) -> [return: bb2, unwind: bb1]; // } // // bb1: { +// resume; +// } +// +// bb2: { // StorageDead(_3); // StorageDead(_8); // StorageDead(_9); @@ -146,10 +150,14 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // _2 = (_3.0: &'12ds S1); // _1 = move _2; // StorageDead(_2); -// drop(_3) -> bb1; +// drop(_3) -> [return: bb2, unwind: bb1]; // } // // bb1: { +// resume; +// } +// +// bb2: { // StorageDead(_3); // StorageDead(_8); // StorageDead(_5); diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index b0adbd6ba89..0e86eae22e5 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -54,56 +54,59 @@ fn main() { // ... // _2 = std::option::Option::Some(const 42i32,); // _5 = discriminant(_2); -// switchInt(move _5) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; +// switchInt(move _5) -> [0isize: bb6, 1isize: bb4, otherwise: bb8]; // } -// bb1: { // arm1 +// bb1: { +// resume; +// } +// bb2: { // arm1 // StorageLive(_7); // _7 = _3; // _1 = (const 1i32, move _7); // StorageDead(_7); -// goto -> bb12; +// goto -> bb13; // } -// bb2: { // binding3(empty) and arm3 +// bb3: { // binding3(empty) and arm3 // _1 = (const 3i32, const 3i32); -// goto -> bb12; -// } -// bb3: { -// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 +// goto -> bb13; // } // bb4: { -// falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2 +// falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1 // } // bb5: { -// falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3 +// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2 // } // bb6: { -// unreachable; +// falseEdges -> [real: bb3, imaginary: bb7]; //pre_binding3 // } // bb7: { // unreachable; // } -// bb8: { // binding1 and guard +// bb8: { +// unreachable; +// } +// bb9: { // binding1 and guard // StorageLive(_3); // _3 = ((_2 as Some).0: i32); // StorageLive(_6); -// _6 = const guard() -> bb9; +// _6 = const guard() -> [return: bb10, unwind: bb1]; // } -// bb9: { // end of guard -// switchInt(move _6) -> [0u8: bb10, otherwise: bb1]; +// bb10: { // end of guard +// switchInt(move _6) -> [0u8: bb11, otherwise: bb2]; // } -// bb10: { // to pre_binding2 -// falseEdges -> [real: bb4, imaginary: bb4]; +// bb11: { // to pre_binding2 +// falseEdges -> [real: bb5, imaginary: bb5]; // } -// bb11: { // bindingNoLandingPads.before.mir2 and arm2 +// bb12: { // bindingNoLandingPads.before.mir2 and arm2 // StorageLive(_4); // _4 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _4; // _1 = (const 2i32, move _8); // StorageDead(_8); -// goto -> bb12; +// goto -> bb13; // } -// bb12: { +// bb13: { // ... // return; // } @@ -114,56 +117,59 @@ fn main() { // ... // _2 = std::option::Option::Some(const 42i32,); // _5 = discriminant(_2); -// switchInt(move _5) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; +// switchInt(move _5) -> [0isize: bb5, 1isize: bb4, otherwise: bb8]; // } -// bb1: { // arm1 +// bb1: { +// resume; +// } +// bb2: { // arm1 // StorageLive(_7); // _7 = _3; // _1 = (const 1i32, move _7); // StorageDead(_7); -// goto -> bb12; +// goto -> bb13; // } -// bb2: { // binding3(empty) and arm3 +// bb3: { // binding3(empty) and arm3 // _1 = (const 3i32, const 3i32); -// goto -> bb12; -// } -// bb3: { -// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 +// goto -> bb13; // } // bb4: { -// falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2 +// falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1 // } // bb5: { -// falseEdges -> [real: bb11, imaginary: bb6]; //pre_binding3 +// falseEdges -> [real: bb3, imaginary: bb6]; //pre_binding2 // } // bb6: { -// unreachable; +// falseEdges -> [real: bb12, imaginary: bb7]; //pre_binding3 // } // bb7: { // unreachable; // } -// bb8: { // binding1 and guard +// bb8: { +// unreachable; +// } +// bb9: { // binding1 and guard // StorageLive(_3); // _3 = ((_2 as Some).0: i32); // StorageLive(_6); -// _6 = const guard() -> bb9; +// _6 = const guard() -> [return: bb10, unwind: bb1]; // } -// bb9: { // end of guard -// switchInt(move _6) -> [0u8: bb10, otherwise: bb1]; +// bb10: { // end of guard +// switchInt(move _6) -> [0u8: bb11, otherwise: bb2]; // } -// bb10: { // to pre_binding2 -// falseEdges -> [real: bb5, imaginary: bb4]; +// bb11: { // to pre_binding2 +// falseEdges -> [real: bb6, imaginary: bb5]; // } -// bb11: { // binding2 and arm2 +// bb12: { // binding2 and arm2 // StorageLive(_4); // _4 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _4; // _1 = (const 2i32, move _8); // StorageDead(_8); -// goto -> bb12; +// goto -> bb13; // } -// bb12: { +// bb13: { // ... // return; // } @@ -174,72 +180,75 @@ fn main() { // ... // _2 = std::option::Option::Some(const 1i32,); // _7 = discriminant(_2); -// switchInt(move _7) -> [1isize: bb3, otherwise: bb4]; +// switchInt(move _7) -> [1isize: bb4, otherwise: bb5]; // } -// bb1: { // arm1 -// _1 = const 1i32; -// goto -> bb16; +// bb1: { +// resume; // } -// bb2: { // arm3 +// bb2: { // arm1 +// _1 = const 1i32; +// goto -> bb17; +// } +// bb3: { // arm3 // _1 = const 3i32; -// goto -> bb16; +// goto -> bb17; // } // -// bb3: { -// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 -// } -// bb4: { -// falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2 -// } -// bb5: { -// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3 -// } -// bb6: { -// falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4 -// } -// bb7: { -// unreachable; -// } -// bb8: { // binding1: Some(w) if guard() -// StorageLive(_3); -// _3 = ((_2 as Some).0: i32); -// StorageLive(_8); -// _8 = const guard() -> bb9; -// } -// bb9: { //end of guard -// switchInt(move _8) -> [0u8: bb10, otherwise: bb1]; -// } -// bb10: { // to pre_binding2 -// falseEdges -> [real: bb4, imaginary: bb4]; -// } -// bb11: { // binding2 & arm2 -// StorageLive(_4); -// _4 = _2; -// _1 = const 2i32; -// goto -> bb16; -// } -// bb12: { // binding3: Some(y) if guard2(y) -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); -// StorageLive(_10); -// StorageLive(_11); -// _11 = _5; -// _10 = const guard2(move _11) -> bb13; -// } -// bb13: { // end of guard2 -// StorageDead(_11); -// switchInt(move _10) -> [0u8: bb14, otherwise: bb2]; -// } -// bb14: { // to pre_binding4 -// falseEdges -> [real: bb6, imaginary: bb6]; -// } -// bb15: { // binding4 & arm4 -// StorageLive(_6); -// _6 = _2; -// _1 = const 4i32; -// goto -> bb16; -// } -// bb16: { +// bb4: { +// falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1 +// } +// bb5: { +// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2 +// } +// bb6: { +// falseEdges -> [real: bb13, imaginary: bb7]; //pre_binding3 +// } +// bb7: { +// falseEdges -> [real: bb16, imaginary: bb8]; //pre_binding4 +// } +// bb8: { +// unreachable; +// } +// bb9: { // binding1: Some(w) if guard() +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb10, unwind: bb1]; +// } +// bb10: { //end of guard +// switchInt(move _8) -> [0u8: bb11, otherwise: bb2]; +// } +// bb11: { // to pre_binding2 +// falseEdges -> [real: bb5, imaginary: bb5]; +// } +// bb12: { // binding2 & arm2 +// StorageLive(_4); +// _4 = _2; +// _1 = const 2i32; +// goto -> bb17; +// } +// bb13: { // binding3: Some(y) if guard2(y) +// StorageLive(_5); +// _5 = ((_2 as Some).0: i32); +// StorageLive(_10); +// StorageLive(_11); +// _11 = _5; +// _10 = const guard2(move _11) -> [return: bb14, unwind: bb1]; +// } +// bb14: { // end of guard2 +// StorageDead(_11); +// switchInt(move _10) -> [0u8: bb15, otherwise: bb3]; +// } +// bb15: { // to pre_binding4 +// falseEdges -> [real: bb7, imaginary: bb7]; +// } +// bb16: { // binding4 & arm4 +// StorageLive(_6); +// _6 = _2; +// _1 = const 4i32; +// goto -> bb17; +// } +// bb17: { // ... // return; // } diff --git a/src/test/mir-opt/nll/liveness-call-subtlety.rs b/src/test/mir-opt/nll/liveness-call-subtlety.rs index 59a1d4891f6..e4dd99f5a1e 100644 --- a/src/test/mir-opt/nll/liveness-call-subtlety.rs +++ b/src/test/mir-opt/nll/liveness-call-subtlety.rs @@ -31,15 +31,15 @@ fn main() { // | Live variables at bb0[0]: [] // StorageLive(_1); // | Live variables at bb0[1]: [] -// _1 = const >::new(const 22usize) -> bb1; +// _1 = const >::new(const 22usize) -> [return: bb2, unwind: bb1]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// | Live variables on entry to bb1: [_1 (drop)] -// bb1: { -// | Live variables at bb1[0]: [_1 (drop)] +// | Live variables on entry to bb2: [_1 (drop)] +// bb2: { +// | Live variables at bb2[0]: [_1 (drop)] // StorageLive(_2); -// | Live variables at bb1[1]: [_1 (drop)] -// _2 = const can_panic() -> [return: bb2, unwind: bb4]; +// | Live variables at bb2[1]: [_1 (drop)] +// _2 = const can_panic() -> [return: bb3, unwind: bb4]; // } // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-drop-intra-block.rs b/src/test/mir-opt/nll/liveness-drop-intra-block.rs index 3e86677956f..8dae7738067 100644 --- a/src/test/mir-opt/nll/liveness-drop-intra-block.rs +++ b/src/test/mir-opt/nll/liveness-drop-intra-block.rs @@ -25,17 +25,17 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | Live variables on entry to bb1: [] -// bb1: { -// | Live variables at bb1[0]: [] +// | Live variables on entry to bb2: [] +// bb2: { +// | Live variables at bb2[0]: [] // _1 = const 55usize; -// | Live variables at bb1[1]: [_1] +// | Live variables at bb2[1]: [_1] // StorageLive(_3); -// | Live variables at bb1[2]: [_1] +// | Live variables at bb2[2]: [_1] // StorageLive(_4); -// | Live variables at bb1[3]: [_1] +// | Live variables at bb2[3]: [_1] // _4 = _1; -// | Live variables at bb1[4]: [_4] -// _3 = const use_x(move _4) -> bb2; +// | Live variables at bb2[4]: [_4] +// _3 = const use_x(move _4) -> [return: bb3, unwind: bb1]; // } // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-interblock.rs b/src/test/mir-opt/nll/liveness-interblock.rs index 32a38a5cd5e..5d799d3d90b 100644 --- a/src/test/mir-opt/nll/liveness-interblock.rs +++ b/src/test/mir-opt/nll/liveness-interblock.rs @@ -29,22 +29,20 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | Live variables on entry to bb2: [_1] -// bb2: { -// | Live variables at bb2[0]: [_1] +// | Live variables on entry to bb3: [_1] +// bb3: { +// | Live variables at bb3[0]: [_1] // StorageLive(_4); -// | Live variables at bb2[1]: [_1] +// | Live variables at bb3[1]: [_1] // _4 = _1; -// | Live variables at bb2[2]: [_4] -// _3 = const make_live(move _4) -> bb4; +// | Live variables at bb3[2]: [_4] +// _3 = const make_live(move _4) -> [return: bb5, unwind: bb1]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// | Live variables on entry to bb3: [] -// bb3: { -// | Live variables at bb3[0]: [] -// _5 = const make_dead() -> bb5; +// | Live variables on entry to bb4: [] +// bb4: { +// | Live variables at bb4[0]: [] +// _5 = const make_dead() -> [return: bb6, unwind: bb1]; // } // END rustc.main.nll.0.mir - - diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index 3aba3ac86ae..36dedeebd53 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -31,26 +31,26 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r: {bb1[1], bb2[0], bb2[1]} -// | '_#2r: {bb1[1], bb2[0], bb2[1]} +// | '_#1r: {bb2[1], bb3[0], bb3[1]} +// | '_#2r: {bb2[1], bb3[0], bb3[1]} // ... // let _2: &'_#2r usize; // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// bb1: { -// | Live variables at bb1[0]: [_1, _3] +// bb2: { +// | Live variables at bb2[0]: [_1, _3] // _2 = &'_#1r _1[_3]; -// | Live variables at bb1[1]: [_2] -// switchInt(const true) -> [0u8: bb3, otherwise: bb2]; +// | Live variables at bb2[1]: [_2] +// switchInt(const true) -> [0u8: bb4, otherwise: bb3]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// bb2: { -// | Live variables at bb2[0]: [_2] +// bb3: { +// | Live variables at bb3[0]: [_2] // StorageLive(_7); -// | Live variables at bb2[1]: [_2] +// | Live variables at bb3[1]: [_2] // _7 = (*_2); -// | Live variables at bb2[2]: [_7] -// _6 = const use_x(move _7) -> bb4; +// | Live variables at bb3[2]: [_7] +// _6 = const use_x(move _7) -> [return: bb5, unwind: bb1]; // } // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs index 6d7aa0a26c8..04a30dc284d 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -44,5 +44,5 @@ unsafe impl<#[may_dangle] T> Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1]} +// | '_#5r: {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]} // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs index 5c28746126a..de2b18fe4af 100644 --- a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs +++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs @@ -36,10 +36,10 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r: {bb1[1], bb2[0], bb2[1]} +// | '_#1r: {bb2[1], bb3[0], bb3[1]} // ... -// | '_#3r: {bb7[2], bb7[3], bb7[4]} -// | '_#4r: {bb1[1], bb2[0], bb2[1], bb7[2], bb7[3], bb7[4]} +// | '_#3r: {bb8[2], bb8[3], bb8[4]} +// | '_#4r: {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]} // ... // let mut _2: &'_#4r usize; // ... diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 35701076730..6a2a7cc7149 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -32,9 +32,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#1r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]} -// | '_#2r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]} -// | '_#3r: {bb1[5], bb1[6], bb2[0], bb2[1]} +// | '_#1r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#2r: {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]} +// | '_#3r: {bb2[5], bb2[6], bb3[0], bb3[1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir // let _2: &'_#2r usize; diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 0706f185d31..1b114419448 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -64,7 +64,7 @@ impl Drop for Droppy { // (_1.0: Aligned) = move _4; // StorageDead(_4); // _0 = (); -// drop(_1) -> bb2; +// drop(_1) -> [return: bb2, unwind: bb1]; // } // } // END rustc.main.EraseRegions.before.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index ad3bbba8d08..35786643648 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,11 +17,11 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyBranches-initial.before.mir // bb0: { -// switchInt(const false) -> [0u8: bb2, otherwise: bb1]; +// switchInt(const false) -> [0u8: bb3, otherwise: bb2]; // } // END rustc.main.SimplifyBranches-initial.before.mir // START rustc.main.SimplifyBranches-initial.after.mir // bb0: { -// goto -> bb2; +// goto -> bb3; // } // END rustc.main.SimplifyBranches-initial.after.mir diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 5b8ba4d8d06..309558ed5b3 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -28,7 +28,7 @@ fn main() { // StorageDead(_3); // _0 = (); // Validate(Release, [_1: std::boxed::Box<[i32]>]); -// drop(_1) -> bb2; +// drop(_1) -> [return: bb2, unwind: bb3]; // } // ... // } From 6594799b2df952720f1597bede925697e7570307 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 30 Nov 2017 00:39:01 +0200 Subject: [PATCH 6/7] add and unignore tests --- ...wck-local-borrow-with-panic-outlives-fn.rs | 23 +++++++++++++++++++ .../nll/region-liveness-drop-no-may-dangle.rs | 3 +-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs diff --git a/src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs b/src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs new file mode 100644 index 00000000000..7009c6f33e6 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z borrowck=mir + +fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) { + let mut z = (0, 0); + *x = Some(&mut z.1); //[ast]~ ERROR [E0597] + //[mir]~^ ERROR [E0597] + panic!("catch me for a dangling pointer!") +} + +fn main() { + cplusplus_mode_exceptionally_unsafe(&mut None); +} diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs index 3d92054b0b2..5569fe7f574 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -13,7 +13,6 @@ // including) the call to `use_x`. The `else` branch is not included. // ignore-tidy-linelength -// ignore-test #46267 // compile-flags:-Znll -Zverbose // ^^^^^^^^^ force compiler to dump more region information @@ -47,5 +46,5 @@ impl Drop for Wrap { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb8[0]} +// | '_#5r: {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]} // END rustc.main.nll.0.mir From ff0b84df58be1f96843f6698cb7d59b2157de14e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 3 Dec 2017 14:50:47 +0200 Subject: [PATCH 7/7] fix tests in wasm --- src/test/mir-opt/match_false_edges.rs | 12 ++++++------ src/test/mir-opt/validate_2.rs | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 0e86eae22e5..1f892b0f958 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -49,7 +49,7 @@ fn main() { // END RUST SOURCE // -// START rustc.full_tested_match.SimplifyBranches-initial.before.mir +// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); @@ -110,9 +110,9 @@ fn main() { // ... // return; // } -// END rustc.full_tested_match.SimplifyBranches-initial.before.mir +// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir // -// START rustc.full_tested_match2.SimplifyBranches-initial.before.mir +// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); @@ -173,9 +173,9 @@ fn main() { // ... // return; // } -// END rustc.full_tested_match2.SimplifyBranches-initial.before.mir +// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir // -// START rustc.main.SimplifyBranches-initial.before.mir +// START rustc.main.QualifyAndPromoteConstants.before.mir // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); @@ -252,4 +252,4 @@ fn main() { // ... // return; // } -// END rustc.main.SimplifyBranches-initial.before.mir +// END rustc.main.QualifyAndPromoteConstants.before.mir diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 309558ed5b3..3776a11b3ab 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -9,6 +9,8 @@ // except according to those terms. // ignore-tidy-linelength +// ignore-wasm32-bare unwinding being disabled causes differences in output +// ignore-wasm64-bare unwinding being disabled causes differences in output // compile-flags: -Z verbose -Z mir-emit-validate=1 fn main() {