diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d6ad74f16a92b..d98bb82aabad1 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -217,9 +217,6 @@ for mir::StatementKind<'gcx> { mir::StatementKind::StorageDead(ref place) => { place.hash_stable(hcx, hasher); } - mir::StatementKind::EndRegion(ref region_scope) => { - region_scope.hash_stable(hcx, hasher); - } mir::StatementKind::EscapeToRaw(ref place) => { place.hash_stable(hcx, hasher); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d8e45c881f555..a9ea1c9a10931 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,6 @@ use hir::def::CtorKind; use hir::def_id::DefId; use hir::{self, HirId, InlineAsm}; -use middle::region; use mir::interpret::{ConstValue, EvalErrorKind, Scalar}; use mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; @@ -1789,10 +1788,6 @@ pub enum StatementKind<'tcx> { /// for more details. EscapeToRaw(Operand<'tcx>), - /// Mark one terminating point of a region scope (i.e. static region). - /// (The starting point(s) arise implicitly from borrows.) - EndRegion(region::Scope), - /// Encodes a user's type ascription. These need to be preserved /// intact so that NLL can respect them. For example: /// @@ -1846,8 +1841,6 @@ impl<'tcx> Debug for Statement<'tcx> { match self.kind { Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), - // (reuse lifetime rendering policy from ppaux.) - EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)), Retag { fn_entry, ref place } => write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, place), EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place), @@ -3028,7 +3021,6 @@ EnumTypeFoldableImpl! { (StatementKind::InlineAsm) { asm, outputs, inputs }, (StatementKind::Retag) { fn_entry, place }, (StatementKind::EscapeToRaw)(place), - (StatementKind::EndRegion)(a), (StatementKind::AscribeUserType)(a, v, b), (StatementKind::Nop), } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 2a994ee0509c2..0c9b06a8d8c7d 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -377,7 +377,6 @@ macro_rules! make_mir_visitor { location ); } - StatementKind::EndRegion(_) => {} StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => { self.visit_place( place, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c620e092f36ca..3fd22793a08a0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1149,8 +1149,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path identify_regions: bool = (false, parse_bool, [UNTRACKED], "make unnamed regions display as '# (where # is some non-ident unique id)"), - emit_end_regions: bool = (false, parse_bool, [UNTRACKED], - "emit EndRegion as part of MIR; enable transforms that solely process EndRegion"), borrowck: Option = (None, parse_opt_string, [UNTRACKED], "select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"), two_phase_borrows: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a8ce52a8e156c..1b947c276f3b3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1540,13 +1540,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Should we emit EndRegion MIR statements? These are consumed by - /// MIR borrowck, but not when NLL is used. - pub fn emit_end_regions(self) -> bool { - self.sess.opts.debugging_opts.emit_end_regions || - self.use_mir_borrowck() - } - #[inline] pub fn local_crate_exports_generics(self) -> bool { debug_assert!(self.sess.opts.share_generics()); diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index a69474142ab58..0d058c85f333b 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -105,7 +105,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx } mir::StatementKind::FakeRead(..) | - mir::StatementKind::EndRegion(..) | mir::StatementKind::Retag { .. } | mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index c432826dca865..fd7dc7fc4bd3a 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -9,6 +9,7 @@ // except according to those terms. use borrow_check::place_ext::PlaceExt; +use borrow_check::nll::ToRegionVid; use dataflow::indexes::BorrowIndex; use dataflow::move_paths::MoveData; use rustc::mir::traversal; @@ -16,7 +17,7 @@ use rustc::mir::visit::{ PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext }; use rustc::mir::{self, Location, Mir, Place, Local}; -use rustc::ty::{Region, TyCtxt}; +use rustc::ty::{RegionVid, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::bit_set::BitSet; @@ -42,7 +43,7 @@ crate struct BorrowSet<'tcx> { /// Every borrow has a region; this maps each such regions back to /// its borrow-indexes. - crate region_map: FxHashMap, FxHashSet>, + crate region_map: FxHashMap>, /// Map from local to all the borrows on that local crate local_map: FxHashMap>, @@ -77,7 +78,7 @@ crate struct BorrowData<'tcx> { /// What kind of borrow this is crate kind: mir::BorrowKind, /// The region for which this borrow is live - crate region: Region<'tcx>, + crate region: RegionVid, /// Place from which we are borrowing crate borrowed_place: mir::Place<'tcx>, /// Place to which the borrow was stored @@ -92,13 +93,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { mir::BorrowKind::Unique => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; - let region = self.region.to_string(); - let separator = if !region.is_empty() { - " " - } else { - "" - }; - write!(w, "&{}{}{}{:?}", region, separator, kind, self.borrowed_place) + write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } } @@ -189,7 +184,7 @@ struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> { idx_vec: IndexVec>, location_map: FxHashMap, activation_map: FxHashMap>, - region_map: FxHashMap, FxHashSet>, + region_map: FxHashMap>, local_map: FxHashMap>, /// When we encounter a 2-phase borrow statement, it will always @@ -219,6 +214,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { return; } + let region = region.to_region_vid(); + let borrow = BorrowData { kind, region, @@ -230,7 +227,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { let idx = self.idx_vec.push(borrow); self.location_map.insert(location, idx); - self.insert_as_pending_if_two_phase(location, &assigned_place, region, kind, idx); + self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); self.region_map.entry(region).or_default().insert(idx); if let Some(local) = borrowed_place.root_local() { @@ -314,7 +311,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { let borrow_data = &self.idx_vec[borrow_index]; assert_eq!(borrow_data.reserve_location, location); assert_eq!(borrow_data.kind, kind); - assert_eq!(borrow_data.region, region); + assert_eq!(borrow_data.region, region.to_region_vid()); assert_eq!(borrow_data.borrowed_place, *place); } @@ -347,13 +344,12 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { &mut self, start_location: Location, assigned_place: &mir::Place<'tcx>, - region: Region<'tcx>, kind: mir::BorrowKind, borrow_index: BorrowIndex, ) { debug!( - "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?}, {:?})", - start_location, assigned_place, region, borrow_index, + "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})", + start_location, assigned_place, borrow_index, ); if !self.allow_two_phase_borrow(kind) { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index f0d3b863f78b2..76ba6ae5de6ee 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -14,7 +14,6 @@ use borrow_check::nll::region_infer::RegionInferenceContext; use rustc::hir; use rustc::hir::Node; use rustc::hir::def_id::DefId; -use rustc::hir::map::definitions::DefPathData; use rustc::infer::InferCtxt; use rustc::lint::builtin::UNUSED_MUT; use rustc::middle::borrowck::SignalledError; @@ -162,10 +161,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( move_data: move_data, param_env: param_env, }; - let body_id = match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::StructCtor | DefPathData::EnumVariant(_) => None, - _ => Some(tcx.hir.body_owned_by(id)), - }; let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); let mut flow_inits = FlowAtLocation::new(do_dataflow( @@ -212,7 +207,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( id, &attributes, &dead_unwinds, - Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set), + Borrows::new(tcx, mir, regioncx.clone(), &borrow_set), |rs, i| DebugFormatted::new(&rs.location(i)), )); let flow_uninits = FlowAtLocation::new(do_dataflow( @@ -592,10 +587,6 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.consume_operand(context, (input, span), flow_state); } } - StatementKind::EndRegion(ref _rgn) => { - // ignored when consuming results (update to - // flow_state already handled). - } StatementKind::Nop | StatementKind::AscribeUserType(..) | StatementKind::Retag { .. } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 2bf531d1d3e56..bb9a29b055b7f 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -206,7 +206,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mir = self.mir; let tcx = self.infcx.tcx; - let borrow_region_vid = regioncx.to_region_vid(borrow.region); + let borrow_region_vid = borrow.region; debug!( "explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 576509c0fddda..8af23a8813a9e 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -132,8 +132,6 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { self.consume_operand(context, input); } } - // EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL - StatementKind::EndRegion(..) | StatementKind::Nop | StatementKind::AscribeUserType(..) | StatementKind::Retag { .. } | diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 363afb87ed909..e9f749ac092d2 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -10,7 +10,7 @@ use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind, UserTypeAnnotation}; +use rustc::mir::{Location, Mir, UserTypeAnnotation}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -119,16 +119,4 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_closure_substs: substs={:?}", substs); } - - fn visit_statement( - &mut self, - block: BasicBlock, - statement: &mut Statement<'tcx>, - location: Location, - ) { - if let StatementKind::EndRegion(_) = statement.kind { - statement.kind = StatementKind::Nop; - } - self.super_statement(block, statement, location); - } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 06dfd4bc2cc1f..b978d8c9d0ae0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1314,7 +1314,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::InlineAsm { .. } - | StatementKind::EndRegion(_) | StatementKind::Retag { .. } | StatementKind::EscapeToRaw { .. } | StatementKind::Nop => {} diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 619ebb1675ca6..2efb75c232d2e 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -14,9 +14,7 @@ //! Routines for manipulating the control-flow graph. use build::CFG; -use rustc::middle::region; use rustc::mir::*; -use rustc::ty::TyCtxt; impl<'tcx> CFG<'tcx> { pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { @@ -45,30 +43,6 @@ impl<'tcx> CFG<'tcx> { self.block_data_mut(block).statements.push(statement); } - pub fn push_end_region<'a, 'gcx:'a+'tcx>(&mut self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - block: BasicBlock, - source_info: SourceInfo, - region_scope: region::Scope) { - if tcx.emit_end_regions() { - if let region::ScopeData::CallSite = region_scope.data { - // The CallSite scope (aka the root scope) is sort of weird, in that it is - // supposed to "separate" the "interior" and "exterior" of a closure. Being - // that, it is not really a part of the region hierarchy, but for some - // reason it *is* considered a part of it. - // - // It should die a hopefully painful death with NLL, so let's leave this hack - // for now so that nobody can complain about soundness. - return - } - - self.push(block, Statement { - source_info, - kind: StatementKind::EndRegion(region_scope), - }); - } - } - pub fn push_assign(&mut self, block: BasicBlock, source_info: SourceInfo, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 99badd5a03fe6..2a11f24095b06 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -90,12 +90,13 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use hair::LintLevel; use rustc::middle::region; -use rustc::ty::{Ty, TyCtxt}; +use rustc::ty::Ty; use rustc::hir; use rustc::hir::def_id::LOCAL_CRATE; use rustc::mir::*; use syntax_pos::{Span}; use rustc_data_structures::fx::FxHashMap; +use std::collections::hash_map::Entry; #[derive(Debug)] pub struct Scope<'tcx> { @@ -224,7 +225,7 @@ impl<'tcx> Scope<'tcx> { /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a /// larger extent of code. /// - /// `storage_only` controls whether to invalidate only drop paths run `StorageDead`. + /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`. /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current /// top-of-scope (as opposed to dependent scopes). fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) { @@ -242,8 +243,8 @@ impl<'tcx> Scope<'tcx> { } if !storage_only && !this_scope_only { - for dropdata in &mut self.drops { - if let DropKind::Value { ref mut cached_block } = dropdata.kind { + for drop_data in &mut self.drops { + if let DropKind::Value { ref mut cached_block } = drop_data.kind { cached_block.invalidate(); } } @@ -323,7 +324,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let parent_hir_id = tcx.hir.definitions().node_to_hir_id( self.source_scope_local_data[source_scope].lint_root - ); + ); let current_hir_id = tcx.hir.definitions().node_to_hir_id(node_id); sets.lint_level_set(parent_hir_id) == @@ -333,7 +334,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if !same_lint_scopes { self.source_scope = self.new_source_scope(region_scope.1.span, lint_level, - None); + None); } } self.push_scope(region_scope); @@ -381,15 +382,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let scope = self.scopes.pop().unwrap(); 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, - self.arg_count, - false)); + let unwind_to = self.scopes.last().and_then(|next_scope| { + next_scope.cached_unwind.get(false) + }).unwrap_or_else(|| self.resume_block()); + + unpack!(block = build_scope_drops( + &mut self.cfg, + &scope, + block, + unwind_to, + self.arg_count, + false, + )); block.unit() } @@ -397,8 +401,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Branch out of `block` to `target`, exiting all scopes up to /// and including `region_scope`. This will insert whatever drops are - /// needed, as well as tracking this exit for the SEME region. See - /// module comment for details. + /// needed. See module comment for details. pub fn exit_scope(&mut self, span: Span, region_scope: (region::Scope, SourceInfo), @@ -416,41 +419,51 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // If we are emitting a `drop` statement, we need to have the cached // diverge cleanup pads ready in case that drop panics. - let may_panic = self.scopes[(len - scope_count)..].iter() - .any(|s| s.drops.iter().any(|s| s.kind.may_panic())); + let may_panic = self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup); if may_panic { self.diverge_cleanup(); } - { - 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_; - block = if let Some(&e) = scope.cached_exits.get(&(target, region_scope.0)) { - self.cfg.terminate(block, scope.source_info(span), - TerminatorKind::Goto { target: e }); - return; - } else { - let b = self.cfg.start_new_block(); - self.cfg.terminate(block, scope.source_info(span), - TerminatorKind::Goto { target: b }); - scope.cached_exits.insert((target, region_scope.0), b); - b + let mut scopes = self.scopes[(len - scope_count - 1)..].iter_mut().rev(); + let mut scope = scopes.next().unwrap(); + for next_scope in scopes { + if scope.drops.is_empty() { + scope = next_scope; + continue; + } + let source_info = scope.source_info(span); + block = match scope.cached_exits.entry((target, region_scope.0)) { + Entry::Occupied(e) => { + self.cfg.terminate(block, source_info, + TerminatorKind::Goto { target: *e.get() }); + return; + } + Entry::Vacant(v) => { + let b = self.cfg.start_new_block(); + self.cfg.terminate(block, source_info, + TerminatorKind::Goto { target: b }); + v.insert(b); + b + } }; - // End all regions for scopes out of which we are breaking. - self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope); + let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| { + debug_assert!(!may_panic, "cached block not present?"); + START_BLOCK + }); - unpack!(block = build_scope_drops(&mut self.cfg, - resume_block, - scope, - rest, - block, - self.arg_count, - false)); - } + unpack!(block = build_scope_drops( + &mut self.cfg, + scope, + block, + unwind_to, + self.arg_count, + false, + )); + + scope = next_scope; } + let scope = &self.scopes[len - scope_count]; self.cfg.terminate(block, scope.source_info(span), TerminatorKind::Goto { target }); @@ -465,20 +478,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { return None; } - // Fill in the cache + // Fill in the cache for unwinds self.diverge_cleanup_gen(true); let src_info = self.scopes[0].source_info(self.fn_span); + let resume_block = self.resume_block(); + let mut scopes = self.scopes.iter_mut().rev().peekable(); 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() { - rest = rest_; + while let Some(scope) = scopes.next() { if !scope.needs_cleanup { continue; } + block = if let Some(b) = scope.cached_generator_drop { self.cfg.terminate(block, src_info, TerminatorKind::Goto { target: b }); @@ -491,16 +504,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { b }; - // End all regions for scopes out of which we are breaking. - 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, - self.arg_count, - true)); + let unwind_to = scopes.peek().as_ref().map(|scope| { + scope.cached_unwind.get(true).unwrap_or_else(|| { + span_bug!(src_info.span, "cached block not present?") + }) + }).unwrap_or(resume_block); + + unpack!(block = build_scope_drops( + &mut self.cfg, + scope, + block, + unwind_to, + self.arg_count, + true, + )); } self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop); @@ -510,9 +527,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Creates a new source scope, nested in the current one. pub fn new_source_scope(&mut self, - span: Span, - lint_level: LintLevel, - safety: Option) -> SourceScope { + span: Span, + lint_level: LintLevel, + safety: Option) -> SourceScope { let parent = self.source_scope; debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}", span, lint_level, safety, @@ -749,8 +766,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Creates a path that performs all required cleanup for unwinding. /// /// 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. + /// See module comment for more details. pub fn diverge_cleanup(&mut self) -> BasicBlock { self.diverge_cleanup_gen(false) } @@ -772,11 +788,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } 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: // @@ -788,11 +799,17 @@ 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. - 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); - } + // Find the last cached block + let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter() + .rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) { + (self.scopes[cached_index].cached_unwind.get(generator_drop).unwrap(), cached_index + 1) + } else { + (self.resume_block(), 0) + }; + + for scope in self.scopes[first_uncached..].iter_mut() { + target = build_diverge_scope(&mut self.cfg, scope.region_scope_span, + scope, target, generator_drop); } target @@ -866,64 +883,62 @@ 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, - arg_count: usize, - generator_drop: bool) - -> BlockAnd<()> { - debug!("build_scope_drops({:?} -> {:?})", block, scope); - let mut iter = scope.drops.iter().rev(); - while let Some(drop_data) = iter.next() { +fn build_scope_drops<'tcx>( + cfg: &mut CFG<'tcx>, + scope: &Scope<'tcx>, + mut block: BasicBlock, + last_unwind_to: BasicBlock, + arg_count: usize, + generator_drop: bool, +) -> BlockAnd<()> { + debug!("build_scope_drops({:?} -> {:?}", block, scope); + + // Build up the drops in evaluation order. The end result will + // look like: + // + // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]] + // | | | + // : | | + // V V + // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to] + // + // The horizontal arrows represent the execution path when the drops return + // successfully. The downwards arrows represent the execution path when the + // drops panic (panicking while unwinding will abort, so there's no need for + // another set of arrows). The drops for the unwind path should have already + // been generated by `diverge_cleanup_gen`. + // + // The code in this function reads from right to left. + // Storage dead drops have to be done left to right (since we can only push + // to the end of a Vec). So, we find the next drop and then call + // push_storage_deads which will iterate backwards through them so that + // they are added in the correct order. + + let mut unwind_blocks = scope.drops.iter().rev().filter_map(|drop_data| { + if let DropKind::Value { cached_block } = drop_data.kind { + Some(cached_block.get(generator_drop).unwrap_or_else(|| { + span_bug!(drop_data.span, "cached block not present?") + })) + } else { + None + } + }); + + // When we unwind from a drop, we start cleaning up from the next one, so + // we don't need this block. + unwind_blocks.next(); + + for drop_data in scope.drops.iter().rev() { let source_info = scope.source_info(drop_data.span); match drop_data.kind { DropKind::Value { .. } => { - // Try to find the next block with its cached block for us to - // diverge into, either a previous block in this current scope or - // the top of the previous scope. - // - // If it wasn't for EndRegion, we could just chain all the DropData - // together and pick the first DropKind::Value. Please do that - // when we replace EndRegion with NLL. - let on_diverge = iter.clone().filter_map(|dd| { - match dd.kind { - DropKind::Value { cached_block } => Some(cached_block), - DropKind::Storage => None - } - }).next().or_else(|| { - if earlier_scopes.iter().any(|scope| scope.needs_cleanup) { - // If *any* scope requires cleanup code to be run, - // we must use the cached unwind from the *topmost* - // scope, to ensure all EndRegions from surrounding - // scopes are executed before the drop code runs. - Some(earlier_scopes.last().unwrap().cached_unwind) - } else { - // We don't need any further cleanup, so return None - // to avoid creating a landing pad. We can skip - // EndRegions because all local regions end anyway - // when the function unwinds. - // - // This is an important optimization because LLVM is - // terrible at optimizing landing pads. FIXME: I think - // it would be cleaner and better to do this optimization - // in SimplifyCfg instead of here. - None - } - }); - - let on_diverge = on_diverge.map(|cached_block| { - cached_block.get(generator_drop).unwrap_or_else(|| { - span_bug!(drop_data.span, "cached block not present?") - }) - }); + let unwind_to = unwind_blocks.next().unwrap_or(last_unwind_to); let next = cfg.start_new_block(); cfg.terminate(block, source_info, TerminatorKind::Drop { location: drop_data.location.clone(), target: next, - unwind: Some(on_diverge.unwrap_or(resume_block)) + unwind: Some(unwind_to) }); block = next; } @@ -950,21 +965,17 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, block.unit() } -fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - cfg: &mut CFG<'tcx>, - span: Span, - scope: &mut Scope<'tcx>, - mut target: BasicBlock, - generator_drop: bool) - -> BasicBlock +fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, + span: Span, + scope: &mut Scope<'tcx>, + mut target: BasicBlock, + generator_drop: bool) + -> BasicBlock { // Build up the drops in **reverse** order. The end result will // look like: // - // [EndRegion Block] -> [drops[n]] -...-> [drops[0]] -> [Free] -> [target] - // | | - // +---------------------------------------------------------+ - // code for scope + // [drops[n]] -...-> [drops[0]] -> [target] // // The code in this function reads from right to left. At each // point, we check for cached blocks representing the @@ -1009,21 +1020,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, }; } - // Finally, push the EndRegion block, used by mir-borrowck, and set - // `cached_unwind` to point to it (Block becomes trivial goto after - // pass that removes all EndRegions). - target = { - let cached_block = scope.cached_unwind.ref_mut(generator_drop); - if let Some(cached_block) = *cached_block { - cached_block - } else { - let block = cfg.start_new_cleanup_block(); - cfg.push_end_region(tcx, block, source_info(span), scope.region_scope); - cfg.terminate(block, source_info(span), TerminatorKind::Goto { target }); - *cached_block = Some(block); - block - } - }; + *scope.cached_unwind.ref_mut(generator_drop) = Some(target); debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 811da9e1acca7..27bc28ac81d84 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -12,18 +12,13 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData}; use borrow_check::place_ext::PlaceExt; use rustc; -use rustc::hir; -use rustc::hir::def_id::DefId; -use rustc::middle::region; use rustc::mir::{self, Location, Place, Mir}; use rustc::ty::TyCtxt; -use rustc::ty::{RegionKind, RegionVid}; -use rustc::ty::RegionKind::ReScope; +use rustc::ty::RegionVid; use rustc_data_structures::bit_set::{BitSet, BitSetOperator}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::Lrc; use dataflow::{BitDenotation, BlockSets, InitialFlow}; pub use dataflow::indexes::BorrowIndex; @@ -42,8 +37,6 @@ use std::rc::Rc; pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - scope_tree: Lrc, - root_scope: Option, borrow_set: Rc>, borrows_out_of_scope_at_location: FxHashMap>, @@ -150,18 +143,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, nonlexical_regioncx: Rc>, - def_id: DefId, - body_id: Option, borrow_set: &Rc>, ) -> Self { - let scope_tree = tcx.region_scope_tree(def_id); - let root_scope = body_id.map(|body_id| { - region::Scope { - id: tcx.hir.body(body_id).value.hir_id.local_id, - data: region::ScopeData::CallSite - } - }); - let mut borrows_out_of_scope_at_location = FxHashMap::default(); for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() { let borrow_region = borrow_data.region.to_region_vid(); @@ -177,8 +160,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { mir: mir, borrow_set: borrow_set.clone(), borrows_out_of_scope_at_location, - scope_tree, - root_scope, _nonlexical_regioncx: nonlexical_regioncx, } } @@ -190,8 +171,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { } /// Add all borrows to the kill set, if those borrows are out of scope at `location`. - /// That means either they went out of either a nonlexical scope, if we care about those - /// at the moment, or the location represents a lexical EndRegion + /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location(&self, sets: &mut BlockSets, location: Location) { @@ -252,9 +232,6 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { }); match stmt.kind { - mir::StatementKind::EndRegion(_) => { - } - mir::StatementKind::Assign(ref lhs, ref rhs) => { // Make sure there are no remaining borrows for variables // that are assigned over. @@ -281,22 +258,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { panic!("could not find BorrowIndex for location {:?}", location); }); - if let RegionKind::ReEmpty = region { - // If the borrowed value dies before the borrow is used, the region for - // the borrow can be empty. Don't track the borrow in that case. - debug!("Borrows::statement_effect_on_borrows \ - location: {:?} stmt: {:?} has empty region, killing {:?}", - location, stmt.kind, index); - sets.kill(*index); - return - } else { - debug!("Borrows::statement_effect_on_borrows location: {:?} stmt: {:?}", - location, stmt.kind); - } - - assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| { - panic!("could not find BorrowIndexs for region {:?}", region); - }).contains(&index)); + assert!(self.borrow_set.region_map + .get(®ion.to_region_vid()) + .unwrap_or_else(|| { + panic!("could not find BorrowIndexs for RegionVid {:?}", region); + }) + .contains(&index) + ); sets.gen(*index); // Issue #46746: Two-phase borrows handles @@ -353,52 +321,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { self.kill_loans_out_of_scope_at_location(sets, location); } - fn terminator_effect(&self, sets: &mut BlockSets, location: Location) { - debug!("Borrows::terminator_effect sets: {:?} location: {:?}", sets, location); - - let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| { - panic!("could not find block at location {:?}", location); - }); - - let term = block.terminator(); - match term.kind { - mir::TerminatorKind::Resume | - mir::TerminatorKind::Return | - mir::TerminatorKind::GeneratorDrop => { - // When we return from the function, then all `ReScope`-style regions - // are guaranteed to have ended. - // Normally, there would be `EndRegion` statements that come before, - // and hence most of these loans will already be dead -- but, in some cases - // like unwind paths, we do not always emit `EndRegion` statements, so we - // add some kills here as a "backup" and to avoid spurious error messages. - for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() { - if let ReScope(scope) = borrow_data.region { - // Check that the scope is not actually a scope from a function that is - // a parent of our closure. Note that the CallSite scope itself is - // *outside* of the closure, for some weird reason. - if let Some(root_scope) = self.root_scope { - if *scope != root_scope && - self.scope_tree.is_subscope_of(*scope, root_scope) - { - sets.kill(borrow_index); - } - } - } - } - } - mir::TerminatorKind::Abort | - mir::TerminatorKind::SwitchInt {..} | - mir::TerminatorKind::Drop {..} | - mir::TerminatorKind::DropAndReplace {..} | - mir::TerminatorKind::Call {..} | - mir::TerminatorKind::Assert {..} | - mir::TerminatorKind::Yield {..} | - mir::TerminatorKind::Goto {..} | - mir::TerminatorKind::FalseEdges {..} | - mir::TerminatorKind::FalseUnwind {..} | - mir::TerminatorKind::Unreachable => {} - } - } + fn terminator_effect(&self, _: &mut BlockSets, _: Location) {} fn propagate_call_return(&self, _in_out: &mut BitSet, diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 0e2376d201fd6..3796b1cc4b0c8 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -301,7 +301,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } - StatementKind::EndRegion(..) | StatementKind::Retag { .. } | StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index ac13e5982dae3..8814118f65be4 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -129,7 +129,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } // Statements we do not track. - EndRegion(..) => {} AscribeUserType(..) => {} // Defined to do nothing. These are added by optimization passes, to avoid changing the diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 4ebeebca2273b..3404772f8255f 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -112,7 +112,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { StatementKind::SetDiscriminant { .. } | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | - StatementKind::EndRegion(..) | StatementKind::Retag { .. } | StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 98311444e2871..c0edd3926d32d 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -10,111 +10,26 @@ //! This module provides two passes: //! -//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements -//! in the MIR. -//! - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements -//! with `Nop`. +//! - [CleanAscribeUserType], that replaces all +//! [StatementKind::AscribeUserType] statements with [StatementKind::Nop]. +//! - [CleanFakeReadsAndBorrows], that replaces all [FakeRead] statements and +//! borrows that are read by [FakeReadCause::ForMatchGuard] fake reads with +//! [StatementKind::Nop]. //! -//! The `CleanEndRegions` "pass" is actually implemented as two +//! The [CleanFakeReadsAndBorrows] "pass" is actually implemented as two //! traversals (aka visits) of the input MIR. The first traversal, -//! `GatherBorrowedRegions`, finds all of the regions in the MIR -//! that are involved in a borrow. -//! -//! The second traversal, `DeleteTrivialEndRegions`, walks over the -//! MIR and removes any `EndRegion` that is applied to a region that -//! was not seen in the previous pass. -//! -//! The `CleanAscribeUserType` pass runs at a distinct time from the -//! `CleanEndRegions` pass. It is important that the `CleanAscribeUserType` -//! pass runs after the MIR borrowck so that the NLL type checker can -//! perform the type assertion when it encounters the `AscribeUserType` -//! statements. +//! [DeleteAndRecordFakeReads], deletes the fake reads and finds the temporaries +//! read by [ForMatchGuard] reads, and [DeleteFakeBorrows] deletes the +//! initialization of those temporaries. use rustc_data_structures::fx::FxHashSet; -use rustc::middle::region; use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; -use rustc::mir::{Rvalue, Statement, StatementKind}; -use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; -use rustc::ty::{Ty, RegionKind, TyCtxt}; -use smallvec::smallvec; +use rustc::mir::{Statement, StatementKind}; +use rustc::mir::visit::MutVisitor; +use rustc::ty::TyCtxt; use transform::{MirPass, MirSource}; -pub struct CleanEndRegions; - -#[derive(Default)] -struct GatherBorrowedRegions { - seen_regions: FxHashSet, -} - -struct DeleteTrivialEndRegions<'a> { - seen_regions: &'a FxHashSet, -} - -impl MirPass for CleanEndRegions { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _source: MirSource, - mir: &mut Mir<'tcx>) { - if !tcx.emit_end_regions() { return; } - - let mut gather = GatherBorrowedRegions::default(); - gather.visit_mir(mir); - - let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; - delete.visit_mir(mir); - } -} - -impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions { - fn visit_rvalue(&mut self, - rvalue: &Rvalue<'tcx>, - location: Location) { - // Gather regions that are used for borrows - if let Rvalue::Ref(r, _, _) = *rvalue { - if let RegionKind::ReScope(ce) = *r { - self.seen_regions.insert(ce); - } - } - self.super_rvalue(rvalue, location); - } - - fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) { - // Gather regions that occur in types - let mut regions = smallvec![]; - for t in ty.walk() { - t.push_regions(&mut regions); - } - for re in regions { - match *re { - RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); } - _ => {}, - } - } - self.super_ty(ty); - } -} - -impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> { - fn visit_statement(&mut self, - block: BasicBlock, - statement: &mut Statement<'tcx>, - location: Location) { - let mut delete_it = false; - - if let StatementKind::EndRegion(ref region_scope) = statement.kind { - if !self.seen_regions.contains(region_scope) { - delete_it = true; - } - } - - if delete_it { - statement.make_nop(); - } - self.super_statement(block, statement, location); - } -} - pub struct CleanAscribeUserType; pub struct DeleteAscribeUserType; diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 6351a6b40cb03..a5b5a7e86d21b 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -12,7 +12,7 @@ //! We want to do this once just before codegen, so codegen does not have to take //! care erasing regions all over the place. //! NOTE: We do NOT erase regions of statements that are relevant for -//! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid, and EndRegion. +//! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; @@ -54,10 +54,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { block: BasicBlock, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::EndRegion(_) = statement.kind { - statement.kind = StatementKind::Nop; - } - self.super_statement(block, statement, location); } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 8d3a04f9f3c2c..a77e9b502ac26 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -209,9 +209,6 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea let mut mir = tcx.mir_built(def_id).steal(); run_passes(tcx, &mut mir, def_id, MirPhase::Const, &[ - // Remove all `EndRegion` statements that are not involved in borrows. - &cleanup_post_borrowck::CleanEndRegions, - // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &type_check::TypeckMir, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 00309b0a3e905..816e85948851e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1168,7 +1168,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::InlineAsm {..} | - StatementKind::EndRegion(_) | StatementKind::Retag { .. } | StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 958e5efe3ec74..13e134ba85928 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -243,7 +243,6 @@ fn check_statement( | StatementKind::StorageDead(_) | StatementKind::Retag { .. } | StatementKind::EscapeToRaw { .. } - | StatementKind::EndRegion(_) | StatementKind::AscribeUserType(..) | StatementKind::Nop => Ok(()), } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 445ffbbcf3407..a31d12baed2b4 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -52,12 +52,9 @@ impl RemoveNoopLandingPads { StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | - StatementKind::EndRegion(_) | StatementKind::AscribeUserType(..) | 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). + // These are all nops in a landing pad } StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => { diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 8f026c706fdf7..f852195b8351a 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -161,7 +161,6 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | - mir::StatementKind::EndRegion(_) | mir::StatementKind::Retag { .. } | mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 68840ed4a4804..fb37f03a1cc41 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -83,7 +83,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record(match statement.kind { StatementKind::Assign(..) => "StatementKind::Assign", StatementKind::FakeRead(..) => "StatementKind::FakeRead", - StatementKind::EndRegion(..) => "StatementKind::EndRegion", StatementKind::Retag { .. } => "StatementKind::Retag", StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw", StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs deleted file mode 100644 index dd1c2bd51260b..0000000000000 --- a/src/test/mir-opt/end_region_1.rs +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z emit-end-regions -// ignore-tidy-linelength - -// This is just about the simplest program that exhibits an EndRegion. - -fn main() { - let a = 3; - let b = &a; -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// let mut _0: (); -// ... -// let _2: &'11_1rs i32; -// ... -// let _1: i32; -// ... -// bb0: { -// StorageLive(_1); -// _1 = const 3i32; -// FakeRead(ForLet, _1); -// StorageLive(_2); -// _2 = &'11_1rs _1; -// FakeRead(ForLet, _2); -// _0 = (); -// EndRegion('11_1rs); -// StorageDead(_2); -// StorageDead(_1); -// return; -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs deleted file mode 100644 index 6b0a28b811007..0000000000000 --- a/src/test/mir-opt/end_region_2.rs +++ /dev/null @@ -1,81 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z emit-end-regions -// ignore-tidy-linelength - -// We will EndRegion for borrows in a loop that occur before break but -// not those after break. - -fn main() { - loop { - let a = true; - let b = &a; - if a { break; } - let c = &a; - } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// let mut _0: (); -// ... -// let _7: &'26_3rs bool; -// ... -// let _3: &'26_1rs bool; -// ... -// let _2: bool; -// ... -// let mut _4: (); -// let mut _5: bool; -// ... -// bb0: { -// goto -> bb1; -// } -// bb1: { -// falseUnwind -> [real: bb2, cleanup: bb3]; -// } -// bb2: { -// StorageLive(_2); -// _2 = const true; -// FakeRead(ForLet, _2); -// StorageLive(_3); -// _3 = &'26_1rs _2; -// FakeRead(ForLet, _3); -// StorageLive(_5); -// _5 = _2; -// switchInt(move _5) -> [false: bb5, otherwise: bb4]; -// } -// bb3: { -// ... -// } -// bb4: { -// _0 = (); -// StorageDead(_5); -// EndRegion('26_1rs); -// StorageDead(_3); -// StorageDead(_2); -// return; -// } -// bb5: { -// _4 = (); -// StorageDead(_5); -// StorageLive(_7); -// _7 = &'26_3rs _2; -// FakeRead(ForLet, _7); -// _1 = (); -// EndRegion('26_3rs); -// StorageDead(_7); -// EndRegion('26_1rs); -// StorageDead(_3); -// StorageDead(_2); -// goto -> bb1; -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs deleted file mode 100644 index d8d48358e53fc..0000000000000 --- a/src/test/mir-opt/end_region_3.rs +++ /dev/null @@ -1,81 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z emit-end-regions -// ignore-tidy-linelength - -// Binding the borrow's subject outside the loop does not increase the -// scope of the borrow. - -fn main() { - let mut a; - loop { - a = true; - let b = &a; - if a { break; } - let c = &a; - } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// let mut _0: (); -// ... -// let _7: &'30_3rs bool; -// ... -// let _3: &'30_1rs bool; -// ... -// let mut _1: bool; -// ... -// let mut _2: (); -// let mut _4: (); -// let mut _5: bool; -// let mut _6: !; -// bb0: { -// StorageLive(_1); -// goto -> bb1; -// } -// bb1: { -// falseUnwind -> [real: bb2, cleanup: bb3]; -// } -// bb2: { -// _1 = const true; -// StorageLive(_3); -// _3 = &'30_1rs _1; -// FakeRead(ForLet, _3); -// StorageLive(_5); -// _5 = _1; -// switchInt(move _5) -> [false: bb5, otherwise: bb4]; -// } -// bb3: { -// ... -// } -// bb4: { -// _0 = (); -// StorageDead(_5); -// EndRegion('30_1rs); -// StorageDead(_3); -// StorageDead(_1); -// return; -// } -// bb5: { -// _4 = (); -// StorageDead(_5); -// StorageLive(_7); -// _7 = &'30_3rs _1; -// FakeRead(ForLet, _7); -// _2 = (); -// EndRegion('30_3rs); -// StorageDead(_7); -// EndRegion('30_1rs); -// StorageDead(_3); -// goto -> bb1; -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs deleted file mode 100644 index 3d15f20bd05f3..0000000000000 --- a/src/test/mir-opt/end_region_4.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z emit-end-regions -// ignore-tidy-linelength - -// Unwinding should EndRegion for in-scope borrows: Direct borrows. - -fn main() { - let d = D(0); - let a = 0; - let b = &a; - foo(*b); - let c = &a; -} - -struct D(i32); -impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } - -fn foo(i: i32) { - if i > 0 { panic!("im positive"); } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// let mut _0: (); -// ... -// let _6: &'31_4rs i32; -// ... -// let _3: &'31_2rs i32; -// ... -// let _2: i32; -// ... -// let _1: D; -// ... -// let mut _4: (); -// let mut _5: i32; -// bb0: { -// StorageLive(_1); -// _1 = D(const 0i32,); -// FakeRead(ForLet, _1); -// StorageLive(_2); -// _2 = const 0i32; -// FakeRead(ForLet, _2); -// StorageLive(_3); -// _3 = &'31_2rs _2; -// FakeRead(ForLet, _3); -// StorageLive(_5); -// _5 = (*_3); -// _4 = const foo(move _5) -> [return: bb2, unwind: bb3]; -// } -// bb1: { -// resume; -// } -// bb2: { -// StorageDead(_5); -// StorageLive(_6); -// _6 = &'31_4rs _2; -// FakeRead(ForLet, _6); -// _0 = (); -// EndRegion('31_4rs); -// StorageDead(_6); -// EndRegion('31_2rs); -// StorageDead(_3); -// StorageDead(_2); -// drop(_1) -> [return: bb4, unwind: bb1]; -// } -// bb3: { -// EndRegion('31_2rs); -// drop(_1) -> bb1; -// } -// bb4: { -// StorageDead(_1); -// return; -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs deleted file mode 100644 index 06d1fbabe1616..0000000000000 --- a/src/test/mir-opt/end_region_5.rs +++ /dev/null @@ -1,77 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions - -// Unwinding should EndRegion for in-scope borrows: Borrowing via by-ref closure. - -fn main() { - let d = D(0); - foo(|| -> i32 { d.0 }); -} - -struct D(i32); -impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } - -fn foo(f: F) where F: FnOnce() -> i32 { - if f() > 0 { panic!("im positive"); } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { -// ... -// let mut _0: (); -// ... -// let _1: D; -// ... -// let mut _2: (); -// let mut _3: [closure@NodeId(28) d:&'18s D]; -// let mut _4: &'18s D; -// bb0: { -// StorageLive(_1); -// _1 = D(const 0i32,); -// FakeRead(ForLet, _1); -// StorageLive(_3); -// StorageLive(_4); -// _4 = &'18s _1; -// _3 = [closure@NodeId(28)] { d: move _4 }; -// StorageDead(_4); -// _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; -// } -// bb1: { -// resume; -// } -// bb2: { -// EndRegion('18s); -// StorageDead(_3); -// _0 = (); -// drop(_1) -> [return: bb4, unwind: bb1]; -// } -// bb3: { -// EndRegion('18s); -// drop(_1) -> bb1; -// } -// bb4: { -// StorageDead(_1); -// return; -// } -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir - -// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(28) d:&'18s D]) -> i32 { -// let mut _0: i32; -// -// bb0: { -// _0 = ((*(_1.0: &'18s D)).0: i32); -// return; -// } -// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs deleted file mode 100644 index d0db23e6de0ee..0000000000000 --- a/src/test/mir-opt/end_region_6.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// Unwinding should EndRegion for in-scope borrows: 2nd borrow within by-ref closure. - -fn main() { - let d = D(0); - foo(|| -> i32 { let r = &d; r.0 }); -} - -struct D(i32); -impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } - -fn foo(f: F) where F: FnOnce() -> i32 { - if f() > 0 { panic!("im positive"); } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { -// let mut _0: (); -// ... -// let _1: D; -// ... -// let mut _2: (); -// let mut _3: [closure@NodeId(33) d:&'24s D]; -// let mut _4: &'24s D; -// bb0: { -// StorageLive(_1); -// _1 = D(const 0i32,); -// FakeRead(ForLet, _1); -// StorageLive(_3); -// StorageLive(_4); -// _4 = &'24s _1; -// _3 = [closure@NodeId(33)] { d: move _4 }; -// StorageDead(_4); -// _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; -// } -// bb1: { -// resume; -// } -// bb2: { -// EndRegion('24s); -// StorageDead(_3); -// _0 = (); -// drop(_1) -> [return: bb4, unwind: bb1]; -// } -// bb3: { -// EndRegion('24s); -// drop(_1) -> bb1; -// } -// bb4: { -// StorageDead(_1); -// return; -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir - -// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(33) d:&'24s D]) -> i32 { -// let mut _0: i32; -// ... -// let _2: &'21_0rs D; -// ... -// bb0: { -// StorageLive(_2); -// _2 = &'21_0rs (*(_1.0: &'24s D)); -// FakeRead(ForLet, _2); -// _0 = ((*_2).0: i32); -// EndRegion('21_0rs); -// StorageDead(_2); -// return; -// } -// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs deleted file mode 100644 index c7df440ebe2f3..0000000000000 --- a/src/test/mir-opt/end_region_7.rs +++ /dev/null @@ -1,91 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// Unwinding should EndRegion for in-scope borrows: Borrow of moved data. - -fn main() { - let d = D(0); - foo(move || -> i32 { let r = &d; r.0 }); -} - -struct D(i32); -impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } - -fn foo(f: F) where F: FnOnce() -> i32 { - if f() > 0 { panic!("im positive"); } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { -// let mut _0: (); -// ... -// let _1: D; -// ... -// let mut _2: (); -// let mut _3: [closure@NodeId(33) d:D]; -// bb0: { -// StorageLive(_1); -// _1 = D(const 0i32,); -// FakeRead(ForLet, _1); -// StorageLive(_3); -// _3 = [closure@NodeId(33)] { d: move _1 }; -// _2 = const foo(move _3) -> [return: bb2, unwind: bb4]; -// } -// bb1: { -// resume; -// } -// bb2: { -// drop(_3) -> [return: bb5, unwind: bb3]; -// } -// bb3: { -// drop(_1) -> bb1; -// } -// bb4: { -// drop(_3) -> bb3; -// } -// bb5: { -// StorageDead(_3); -// _0 = (); -// drop(_1) -> [return: bb6, unwind: bb1]; -// } -// bb6: { -// StorageDead(_1); -// return; -// } -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir - -// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(33) d:D]) -> i32 { -// let mut _0: i32; -// ... -// let _2: &'21_0rs D; -// ... -// bb0: { -// StorageLive(_2); -// _2 = &'21_0rs (_1.0: D); -// FakeRead(ForLet, _2); -// _0 = ((*_2).0: i32); -// EndRegion('21_0rs); -// StorageDead(_2); -// drop(_1) -> [return: bb2, unwind: bb1]; -// } -// bb1: { -// resume; -// } -// bb2: { -// return; -// } -// } -// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs deleted file mode 100644 index 9f2a9c3b72e8b..0000000000000 --- a/src/test/mir-opt/end_region_8.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// Unwinding should EndRegion for in-scope borrows: Move of borrow into closure. - -fn main() { - let d = D(0); - let r = &d; - foo(move || -> i32 { r.0 }); -} - -struct D(i32); -impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } - -fn foo(f: F) where F: FnOnce() -> i32 { - if f() > 0 { panic!("im positive"); } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { -// let mut _0: (); -// ... -// let _2: &'26_1rs D; -// ... -// let _1: D; -// ... -// let mut _3: (); -// let mut _4: [closure@NodeId(33) r:&'24s D]; -// bb0: { -// StorageLive(_1); -// _1 = D(const 0i32,); -// FakeRead(ForLet, _1); -// StorageLive(_2); -// _2 = &'26_1rs _1; -// FakeRead(ForLet, _2); -// StorageLive(_4); -// _4 = [closure@NodeId(33)] { r: _2 }; -// _3 = const foo(move _4) -> [return: bb2, unwind: bb3]; -// } -// bb1: { -// resume; -// } -// bb2: { -// EndRegion('24s); -// StorageDead(_4); -// _0 = (); -// EndRegion('26_1rs); -// StorageDead(_2); -// drop(_1) -> [return: bb4, unwind: bb1]; -// } -// bb3: { -// EndRegion('24s); -// EndRegion('26_1rs); -// drop(_1) -> bb1; -// } -// bb4: { -// StorageDead(_1); -// return; -// } -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir - -// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(33) r:&'24s D]) -> i32 { -// let mut _0: i32; -// -// bb0: { -// _0 = ((*(_1.0: &'26_1rs D)).0: i32); -// return; -// } -// } -// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs deleted file mode 100644 index ef2d949d3074e..0000000000000 --- a/src/test/mir-opt/end_region_9.rs +++ /dev/null @@ -1,97 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// This test models a scenario that arielb1 found during review. -// Namely, any filtering of EndRegions must ensure to continue to emit -// any necessary EndRegions that occur earlier in the source than the -// first borrow involving that region. -// -// It is tricky to actually construct examples of this, which is the -// main reason that I am keeping this test even though I have now -// removed the pre-filter that motivated the test in the first place. - -fn main() { - let mut second_iter = false; - let x = 3; - 'a: loop { - let mut y; - loop { - if second_iter { - break 'a; // want to generate `EndRegion('a)` here - } else { - y = &/*'a*/ x; - } - second_iter = true; - } - } -} - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { -// let mut _0: (); -// ... -// let mut _4: &'37_0rs i32; -// ... -// let _2: i32; -// ... -// let mut _1: bool; -// ... -// let mut _3: (); -// let mut _5: !; -// let mut _6: (); -// let mut _7: bool; -// let mut _8: !; -// bb0: { -// StorageLive(_1); -// _1 = const false; -// FakeRead(ForLet, _1); -// StorageLive(_2); -// _2 = const 3i32; -// FakeRead(ForLet, _2); -// falseUnwind -> [real: bb2, cleanup: bb1]; -// } -// bb1: { -// ... -// } -// bb2: { -// StorageLive(_4); -// goto -> bb3; -// } -// bb3: { -// falseUnwind -> [real: bb4, cleanup: bb1]; -// } -// bb4: { -// StorageLive(_7); -// _7 = _1; -// switchInt(move _7) -> [false: bb6, otherwise: bb5]; -// } -// bb5: { -// _0 = (); -// StorageDead(_7); -// EndRegion('37_0rs); -// StorageDead(_4); -// StorageDead(_2); -// StorageDead(_1); -// return; -// } -// bb6: { -// _4 = &'37_0rs _2; -// _6 = (); -// StorageDead(_7); -// _1 = const true; -// _3 = (); -// goto -> bb3; -// } -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs deleted file mode 100644 index 3dbc73caf65d8..0000000000000 --- a/src/test/mir-opt/end_region_cyclic.rs +++ /dev/null @@ -1,141 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// This test models a scenario with a cyclic reference. Rust obviously -// needs to handle such cases. -// -// The interesting part about this test is that such case shows that -// one cannot generally force all references to be dead before you hit -// their EndRegion; at least, not without breaking the more important -// property that all borrowed storage locations have their regions -// ended strictly before their StorageDeads. (This test was inspired -// by discussion on Issue #43481.) - -use std::cell::Cell; - -struct S<'a> { - r: Cell>>, -} - -fn main() { - loop { - let x = S { r: Cell::new(None) }; - x.r.set(Some(&x)); - if query() { break; } - x.r.set(Some(&x)); - } -} - -fn query() -> bool { true } - -// END RUST SOURCE -// START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> (){ -// let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _2: S<'49_0rs>; -// } -// let mut _1: (); -// let mut _3: std::cell::Cell>>; -// let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>; -// let mut _5: (); -// let mut _6: &'25s std::cell::Cell>>; -// let mut _7: std::option::Option<&'49_0rs S<'49_0rs>>; -// let mut _8: &'49_0rs S<'49_0rs>; -// let mut _9: &'49_0rs S<'49_0rs>; -// let mut _10: (); -// let mut _11: bool; -// let mut _12: !; -// let mut _13: (); -// let mut _14: &'47s std::cell::Cell>>; -// let mut _15: std::option::Option<&'49_0rs S<'49_0rs>>; -// let mut _16: &'49_0rs S<'49_0rs>; -// let mut _17: &'49_0rs S<'49_0rs>; -// bb0: { -// goto -> bb1; -// } -// bb1: { -// falseUnwind -> [real: bb2, cleanup: bb3]; -// } -// bb2: { -// StorageLive(_2); -// StorageLive(_3); -// StorageLive(_4); -// _4 = std::option::Option<&'49_0rs S<'49_0rs>>::None; -// _3 = const >::new(move _4) -> [return: bb4, unwind: bb3]; -// } -// bb3: { -// resume; -// } -// bb4: { -// StorageDead(_4); -// _2 = S<'49_0rs> { r: move _3 }; -// StorageDead(_3); -// FakeRead(ForLet, _2); -// StorageLive(_6); -// _6 = &'25s (_2.0: std::cell::Cell>>); -// StorageLive(_7); -// StorageLive(_8); -// StorageLive(_9); -// _9 = &'49_0rs _2; -// _8 = &'49_0rs (*_9); -// _7 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _8,); -// StorageDead(_8); -// _5 = const >::set(move _6, move _7) -> [return: bb5, unwind: bb3]; -// } -// bb5: { -// EndRegion('25s); -// StorageDead(_7); -// StorageDead(_6); -// StorageDead(_9); -// StorageLive(_11); -// _11 = const query() -> [return: bb6, unwind: bb3]; -// } -// bb6: { -// switchInt(move _11) -> [false: bb8, otherwise: bb7]; -// } -// bb7: { -// _0 = (); -// StorageDead(_11); -// EndRegion('49_0rs); -// StorageDead(_2); -// return; -// } -// bb8: { -// _10 = (); -// StorageDead(_11); -// StorageLive(_14); -// _14 = &'47s (_2.0: std::cell::Cell>>); -// StorageLive(_15); -// StorageLive(_16); -// StorageLive(_17); -// _17 = &'49_0rs _2; -// _16 = &'49_0rs (*_17); -// _15 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _16,); -// StorageDead(_16); -// _13 = const >::set(move _14, move _15) -> [return: bb9, unwind: bb3]; -// } -// bb9: { -// EndRegion('47s); -// StorageDead(_15); -// StorageDead(_14); -// StorageDead(_17); -// _1 = (); -// EndRegion('49_0rs); -// StorageDead(_2); -// goto -> bb1; -// } -// } -// END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs deleted file mode 100644 index eb381dfc5521f..0000000000000 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ /dev/null @@ -1,154 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// A scenario with significant destruction code extents (which have -// suffix "dce" in current `-Z identify_regions` rendering). - -#![feature(dropck_eyepatch)] - -fn main() { - // Since the second param to `D1` is may_dangle, it is legal for - // the region of that parameter to end before the drop code for D1 - // is executed. - (D1(&S1("ex1"), &S1("dang1"))).0; -} - -#[derive(Debug)] -struct S1(&'static str); - -#[derive(Debug)] -struct D1<'a, 'b>(&'a S1, &'b S1); - -// The `#[may_dangle]` means that references of type `&'b _` may be -// invalid during the execution of this destructor; i.e. in this case -// the destructor code is not allowed to read or write `*self.1`, while -// it can read/write `*self.0`. -unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { - fn drop(&mut self) { - println!("D1({:?}, _)", self.0); - } -} - -// Notes on the MIR output below: -// -// 1. The `EndRegion('13s)` is allowed to precede the `drop(_3)` -// solely because of the #[may_dangle] mentioned above. -// -// 2. Regarding the occurrence of `EndRegion('15ds)` *after* `StorageDead(_6)` -// (where we have borrows `&'15ds _6`): Eventually: -// -// i. this code should be rejected (by mir-borrowck), or -// -// ii. the MIR code generation should be changed so that the -// EndRegion('15ds)` precedes `StorageDead(_6)` in the -// control-flow. (Note: arielb1 views drop+storagedead as one -// unit, and does not see this option as a useful avenue to -// explore.), or -// -// iii. the presence of EndRegion should be made irrelevant by a -// transformation encoding the effects of rvalue-promotion. -// This may be the simplest and most-likely option; note in -// particular that `StorageDead(_6)` goes away below in -// rustc.main.QualifyAndPromoteConstants.after.mir - -// END RUST SOURCE - -// START rustc.main.QualifyAndPromoteConstants.before.mir -// fn main() -> () { -// let mut _0: (); -// let mut _1: &'15ds S1; -// let mut _2: D1<'15ds, '13s>; -// let mut _3: &'15ds S1; -// let mut _4: &'15ds S1; -// let _5: S1; -// let mut _6: &'13s S1; -// let mut _7: &'13s S1; -// let _8: S1; -// bb0: { -// StorageLive(_2); -// StorageLive(_3); -// StorageLive(_4); -// StorageLive(_5); -// _5 = S1(const "ex1",); -// _4 = &'15ds _5; -// _3 = &'15ds (*_4); -// StorageLive(_6); -// StorageLive(_7); -// StorageLive(_8); -// _8 = S1(const "dang1",); -// _7 = &'13s _8; -// _6 = &'13s (*_7); -// _2 = D1<'15ds, '13s>(move _3, move _6); -// EndRegion('13s); -// StorageDead(_6); -// StorageDead(_3); -// _1 = (_2.0: &'15ds S1); -// drop(_2) -> [return: bb2, unwind: bb1]; -// } -// bb1: { -// resume; -// } -// bb2: { -// StorageDead(_2); -// StorageDead(_7); -// StorageDead(_8); -// StorageDead(_4); -// StorageDead(_5); -// EndRegion('15ds); -// _0 = (); -// return; -// } -// } -// END rustc.main.QualifyAndPromoteConstants.before.mir - -// START rustc.main.QualifyAndPromoteConstants.after.mir -// fn main() -> (){ -// let mut _0: (); -// let mut _1: &'15ds S1; -// let mut _2: D1<'15ds, '13s>; -// let mut _3: &'15ds S1; -// let mut _4: &'15ds S1; -// let _5: S1; -// let mut _6: &'13s S1; -// let mut _7: &'13s S1; -// let _8: S1; -// bb0: { -// StorageLive(_2); -// StorageLive(_3); -// StorageLive(_4); -// _4 = &'15ds (promoted[1]: S1); -// _3 = &'15ds (*_4); -// StorageLive(_6); -// StorageLive(_7); -// _7 = &'13s (promoted[0]: S1); -// _6 = &'13s (*_7); -// _2 = D1<'15ds, '13s>(move _3, move _6); -// EndRegion('13s); -// StorageDead(_6); -// StorageDead(_3); -// _1 = (_2.0: &'15ds S1); -// drop(_2) -> [return: bb2, unwind: bb1]; -// } -// bb1: { -// resume; -// } -// bb2: { -// StorageDead(_2); -// StorageDead(_7); -// StorageDead(_4); -// EndRegion('15ds); -// _0 = (); -// return; -// } -// } -// END rustc.main.QualifyAndPromoteConstants.after.mir diff --git a/src/test/mir-opt/issue-43457.rs b/src/test/mir-opt/issue-43457.rs deleted file mode 100644 index 85cecc5070cd5..0000000000000 --- a/src/test/mir-opt/issue-43457.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions -// ignore-tidy-linelength - -// Regression test for #43457: an `EndRegion` was missing from output -// because compiler was using a faulty means for region map lookup. - -use std::cell::RefCell; - -fn rc_refcell_test(r: RefCell) { - r.borrow_mut(); -} - -fn main() { } - -// END RUST SOURCE -// START rustc.rc_refcell_test.SimplifyCfg-qualify-consts.after.mir -// -// fn rc_refcell_test(_1: std::cell::RefCell) -> () { -// let mut _0: (); -// scope 1 { -// let _2: std::cell::RefCell; -// } -// let mut _3: std::cell::RefMut<'17ds, i32>; -// let mut _4: &'17ds std::cell::RefCell; -// -// bb0: { -// StorageLive(_2); -// _2 = _1; -// StorageLive(_4); -// _4 = &'17ds _2; -// _3 = const >::borrow_mut(_4) -> bb1; -// } -// -// bb1: { -// drop(_3) -> bb2; -// } -// -// bb2: { -// StorageDead(_4); -// EndRegion('17ds); -// _0 = (); -// StorageDead(_2); -// return; -// } -// } diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index f9024b6706334..d8365c8c9cc23 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -44,7 +44,7 @@ fn main() { // falseUnwind -> [real: bb3, cleanup: bb4]; // } // bb2: { -// goto -> bb29; +// goto -> bb20; // } // bb3: { // StorageLive(_2); @@ -90,58 +90,31 @@ fn main() { // StorageDead(_3); // StorageLive(_6); // _6 = &_2; -// _5 = const std::mem::drop(move _6) -> [return: bb28, unwind: bb4]; +// _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4]; // } // bb15: { +// StorageDead(_3); // goto -> bb16; // } // bb16: { -// goto -> bb17; -// } -// bb17: { -// goto -> bb18; -// } -// bb18: { -// goto -> bb19; -// } -// bb19: { -// goto -> bb20; -// } -// bb20: { -// StorageDead(_3); -// goto -> bb21; -// } -// bb21: { -// goto -> bb22; -// } -// bb22: { // StorageDead(_2); -// goto -> bb23; -// } -// bb23: { -// goto -> bb24; -// } -// bb24: { -// goto -> bb25; -// } -// bb25: { // goto -> bb2; // } -// bb26: { +// bb17: { // _4 = (); // unreachable; // } -// bb27: { +// bb18: { // StorageDead(_4); // goto -> bb14; // } -// bb28: { +// bb19: { // StorageDead(_6); // _1 = (); // StorageDead(_2); // goto -> bb1; // } -// bb29: { +// bb20: { // return; // } // } diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs index 2e526a221cc72..77616f1d39ad4 100644 --- a/src/test/mir-opt/loop_test.rs +++ b/src/test/mir-opt/loop_test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z identify_regions -Z emit-end-regions +// compile-flags: -Z identify_regions // Tests to make sure we correctly generate falseUnwind edges in loops diff --git a/src/test/run-pass/issues/issue-16671.rs b/src/test/run-pass/issues/issue-16671.rs index 5ff2bc97ae236..14bda56dd8fbe 100644 --- a/src/test/run-pass/issues/issue-16671.rs +++ b/src/test/run-pass/issues/issue-16671.rs @@ -9,7 +9,7 @@ // except according to those terms. // run-pass -//compile-flags: -Z borrowck=compare -Z emit-end-regions +//compile-flags: -Z borrowck=compare #![deny(warnings)] diff --git a/src/test/ui/borrowck/immutable-arg.rs b/src/test/ui/borrowck/immutable-arg.rs index 7c387ed080821..c5291ab3e1dbf 100644 --- a/src/test/ui/borrowck/immutable-arg.rs +++ b/src/test/ui/borrowck/immutable-arg.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//compile-flags: -Z emit-end-regions -Z borrowck=compare +//compile-flags: -Z borrowck=compare fn foo(_x: u32) { _x = 4; diff --git a/src/test/ui/issues/issue-45697-1.rs b/src/test/ui/issues/issue-45697-1.rs index b8be209833a6e..e79bfb23b05af 100644 --- a/src/test/ui/issues/issue-45697-1.rs +++ b/src/test/ui/issues/issue-45697-1.rs @@ -11,7 +11,7 @@ // Test that assignments to an `&mut` pointer which is found in a // borrowed (but otherwise non-aliasable) location is illegal. -// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=on +// compile-flags: -Z borrowck=compare -C overflow-checks=on struct S<'a> { pointer: &'a mut isize diff --git a/src/test/ui/issues/issue-45697.rs b/src/test/ui/issues/issue-45697.rs index 27acc2c89f75d..936e8a40fa83f 100644 --- a/src/test/ui/issues/issue-45697.rs +++ b/src/test/ui/issues/issue-45697.rs @@ -11,7 +11,7 @@ // Test that assignments to an `&mut` pointer which is found in a // borrowed (but otherwise non-aliasable) location is illegal. -// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=off +// compile-flags: -Z borrowck=compare -C overflow-checks=off struct S<'a> { pointer: &'a mut isize diff --git a/src/test/ui/issues/issue-46023.rs b/src/test/ui/issues/issue-46023.rs index d5c8cd6d0f8fc..ea7e627eadf10 100644 --- a/src/test/ui/issues/issue-46023.rs +++ b/src/test/ui/issues/issue-46023.rs @@ -9,7 +9,7 @@ // except according to those terms. // revisions: ast mir -//[mir]compile-flags: -Z emit-end-regions -Z borrowck=mir +//[mir]compile-flags: -Z borrowck=mir fn main() { let x = 0; diff --git a/src/test/ui/issues/issue-46471-1.rs b/src/test/ui/issues/issue-46471-1.rs index 0dbcdea89f940..7fb77f9ce8bf6 100644 --- a/src/test/ui/issues/issue-46471-1.rs +++ b/src/test/ui/issues/issue-46471-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z emit-end-regions -Z borrowck=compare +// compile-flags: -Z borrowck=compare fn main() { let y = { diff --git a/src/test/ui/issues/issue-46471.rs b/src/test/ui/issues/issue-46471.rs index 654a3d8f964d2..201b8e2de9a79 100644 --- a/src/test/ui/issues/issue-46471.rs +++ b/src/test/ui/issues/issue-46471.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z emit-end-regions -Z borrowck=compare +// compile-flags: -Z borrowck=compare fn foo() -> &'static u32 { let x = 0; diff --git a/src/test/ui/issues/issue-46472.rs b/src/test/ui/issues/issue-46472.rs index 8137cd2dd8913..b6838a48b1b68 100644 --- a/src/test/ui/issues/issue-46472.rs +++ b/src/test/ui/issues/issue-46472.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z emit-end-regions -Z borrowck=compare +// compile-flags: -Z borrowck=compare fn bar<'a>() -> &'a mut u32 { &mut 4 diff --git a/src/test/ui/moves/moves-based-on-type-tuple.rs b/src/test/ui/moves/moves-based-on-type-tuple.rs index 27903fee117b3..9dda275d95eaa 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.rs +++ b/src/test/ui/moves/moves-based-on-type-tuple.rs @@ -10,7 +10,7 @@ #![feature(box_syntax)] -// compile-flags: -Z emit-end-regions -Z borrowck=compare +// compile-flags: -Z borrowck=compare fn dup(x: Box) -> Box<(Box,Box)> { box (x, x) diff --git a/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs b/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs index ae815a5efe97c..f96e73ce09f5f 100644 --- a/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs +++ b/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z emit-end-regions -Zborrowck=mir +// compile-flags: -Zborrowck=mir // compile-pass #![allow(warnings)] diff --git a/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs b/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs index 00d146e0f02d6..0e9cdf2f428ad 100644 --- a/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs +++ b/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//compile-flags: -Z emit-end-regions -Zborrowck=mir +//compile-flags: -Zborrowck=mir #![allow(warnings)] diff --git a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs index cd46014a7f5ca..080fdfe022801 100644 --- a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs +++ b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//compile-flags: -Z emit-end-regions -Zborrowck=mir +//compile-flags: -Zborrowck=mir #![allow(warnings)] diff --git a/src/test/ui/nll/maybe-initialized-drop.rs b/src/test/ui/nll/maybe-initialized-drop.rs index 9a3aca346208d..db680ef8bea17 100644 --- a/src/test/ui/nll/maybe-initialized-drop.rs +++ b/src/test/ui/nll/maybe-initialized-drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//compile-flags: -Z emit-end-regions -Zborrowck=mir +//compile-flags: -Zborrowck=mir #![allow(warnings)]