Auto merge of #55959 - matthewjasper:remove-end-region, r=nikomatsakis

Cleanup from lexical MIR borrowck removal

Lexical MIR borrowck was removed months ago now, and `EndRegion`s are no longer used for MIRI verification.

* Remove `rustc::mir::StatementKind::EndRegion` and the `-Zemit_end_regions` flag
* Use `RegionVid` instead of `Region` in BorrowSet
* Rewrite drop generation to create fewer goto terminators.

r? @nikomatsakis
This commit is contained in:
bors 2018-11-25 03:00:30 +00:00
commit 37961dbd2d
53 changed files with 206 additions and 1559 deletions

View File

@ -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);
}

View File

@ -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),
}

View File

@ -377,7 +377,6 @@ macro_rules! make_mir_visitor {
location
);
}
StatementKind::EndRegion(_) => {}
StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
self.visit_place(
place,

View File

@ -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<String> = (None, parse_opt_string, [UNTRACKED],
"select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],

View File

@ -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());

View File

@ -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(..) |

View File

@ -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<Region<'tcx>, FxHashSet<BorrowIndex>>,
crate region_map: FxHashMap<RegionVid, FxHashSet<BorrowIndex>>,
/// Map from local to all the borrows on that local
crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
@ -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<BorrowIndex, BorrowData<'tcx>>,
location_map: FxHashMap<Location, BorrowIndex>,
activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
region_map: FxHashMap<RegionVid, FxHashSet<BorrowIndex>>,
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
/// 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) {

View File

@ -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 { .. }

View File

@ -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

View File

@ -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 { .. } |

View File

@ -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);
}
}

View File

@ -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 => {}

View File

@ -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,

View File

@ -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);
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,
resume_block,
scope,
rest,
block,
self.arg_count,
true));
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<Safety>) -> SourceScope {
span: Span,
lint_level: LintLevel,
safety: Option<Safety>) -> 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 theres 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);

View File

@ -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<region::ScopeTree>,
root_scope: Option<region::Scope>,
borrow_set: Rc<BorrowSet<'tcx>>,
borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
@ -150,18 +143,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>,
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
def_id: DefId,
body_id: Option<hir::BodyId>,
borrow_set: &Rc<BorrowSet<'tcx>>,
) -> 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<BorrowIndex>,
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(&region.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<BorrowIndex>, 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<BorrowIndex>, _: Location) {}
fn propagate_call_return(&self,
_in_out: &mut BitSet<BorrowIndex>,

View File

@ -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(..) |

View File

@ -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

View File

@ -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(..) |

View File

@ -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<region::Scope>,
}
struct DeleteTrivialEndRegions<'a> {
seen_regions: &'a FxHashSet<region::Scope>,
}
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;

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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(..) |

View File

@ -243,7 +243,6 @@ fn check_statement(
| StatementKind::StorageDead(_)
| StatementKind::Retag { .. }
| StatementKind::EscapeToRaw { .. }
| StatementKind::EndRegion(_)
| StatementKind::AscribeUserType(..)
| StatementKind::Nop => Ok(()),
}

View File

@ -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(_)) => {

View File

@ -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(..) |

View File

@ -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",

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Option<&'a S<'a>>>,
}
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<std::option::Option<&'49_0rs S<'49_0rs>>>;
// let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>;
// let mut _5: ();
// let mut _6: &'25s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
// 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<std::option::Option<&'49_0rs S<'49_0rs>>>;
// 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 <std::cell::Cell<T>>::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<std::option::Option<&'49_0rs S<'49_0rs>>>);
// 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 <std::cell::Cell<T>>::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<std::option::Option<&'49_0rs S<'49_0rs>>>);
// 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 <std::cell::Cell<T>>::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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<i32>) {
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<i32>) -> () {
// let mut _0: ();
// scope 1 {
// let _2: std::cell::RefCell<i32>;
// }
// let mut _3: std::cell::RefMut<'17ds, i32>;
// let mut _4: &'17ds std::cell::RefCell<i32>;
//
// bb0: {
// StorageLive(_2);
// _2 = _1;
// StorageLive(_4);
// _4 = &'17ds _2;
// _3 = const <std::cell::RefCell<T>>::borrow_mut(_4) -> bb1;
// }
//
// bb1: {
// drop(_3) -> bb2;
// }
//
// bb2: {
// StorageDead(_4);
// EndRegion('17ds);
// _0 = ();
// StorageDead(_2);
// return;
// }
// }

View File

@ -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;
// }
// }

View File

@ -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

View File

@ -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)]

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 = {

View File

@ -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;

View File

@ -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

View File

@ -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<isize>) -> Box<(Box<isize>,Box<isize>)> {
box (x, x)

View File

@ -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)]

View File

@ -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)]

View File

@ -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)]

View File

@ -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)]