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:
commit
37961dbd2d
|
@ -217,9 +217,6 @@ for mir::StatementKind<'gcx> {
|
||||||
mir::StatementKind::StorageDead(ref place) => {
|
mir::StatementKind::StorageDead(ref place) => {
|
||||||
place.hash_stable(hcx, hasher);
|
place.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
mir::StatementKind::EndRegion(ref region_scope) => {
|
|
||||||
region_scope.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
mir::StatementKind::EscapeToRaw(ref place) => {
|
mir::StatementKind::EscapeToRaw(ref place) => {
|
||||||
place.hash_stable(hcx, hasher);
|
place.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
use hir::def::CtorKind;
|
use hir::def::CtorKind;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::{self, HirId, InlineAsm};
|
use hir::{self, HirId, InlineAsm};
|
||||||
use middle::region;
|
|
||||||
use mir::interpret::{ConstValue, EvalErrorKind, Scalar};
|
use mir::interpret::{ConstValue, EvalErrorKind, Scalar};
|
||||||
use mir::visit::MirVisitable;
|
use mir::visit::MirVisitable;
|
||||||
use rustc_apfloat::ieee::{Double, Single};
|
use rustc_apfloat::ieee::{Double, Single};
|
||||||
|
@ -1789,10 +1788,6 @@ pub enum StatementKind<'tcx> {
|
||||||
/// for more details.
|
/// for more details.
|
||||||
EscapeToRaw(Operand<'tcx>),
|
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
|
/// Encodes a user's type ascription. These need to be preserved
|
||||||
/// intact so that NLL can respect them. For example:
|
/// intact so that NLL can respect them. For example:
|
||||||
///
|
///
|
||||||
|
@ -1846,8 +1841,6 @@ impl<'tcx> Debug for Statement<'tcx> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
|
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
|
||||||
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
|
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 } =>
|
Retag { fn_entry, ref place } =>
|
||||||
write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, place),
|
write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, place),
|
||||||
EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place),
|
EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place),
|
||||||
|
@ -3028,7 +3021,6 @@ EnumTypeFoldableImpl! {
|
||||||
(StatementKind::InlineAsm) { asm, outputs, inputs },
|
(StatementKind::InlineAsm) { asm, outputs, inputs },
|
||||||
(StatementKind::Retag) { fn_entry, place },
|
(StatementKind::Retag) { fn_entry, place },
|
||||||
(StatementKind::EscapeToRaw)(place),
|
(StatementKind::EscapeToRaw)(place),
|
||||||
(StatementKind::EndRegion)(a),
|
|
||||||
(StatementKind::AscribeUserType)(a, v, b),
|
(StatementKind::AscribeUserType)(a, v, b),
|
||||||
(StatementKind::Nop),
|
(StatementKind::Nop),
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,6 @@ macro_rules! make_mir_visitor {
|
||||||
location
|
location
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StatementKind::EndRegion(_) => {}
|
|
||||||
StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
|
StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
|
||||||
self.visit_place(
|
self.visit_place(
|
||||||
place,
|
place,
|
||||||
|
|
|
@ -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
|
"when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
|
||||||
identify_regions: bool = (false, parse_bool, [UNTRACKED],
|
identify_regions: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"make unnamed regions display as '# (where # is some non-ident unique id)"),
|
"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],
|
borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||||
"select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
|
"select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
|
||||||
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
|
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
|
|
@ -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]
|
#[inline]
|
||||||
pub fn local_crate_exports_generics(self) -> bool {
|
pub fn local_crate_exports_generics(self) -> bool {
|
||||||
debug_assert!(self.sess.opts.share_generics());
|
debug_assert!(self.sess.opts.share_generics());
|
||||||
|
|
|
@ -105,7 +105,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx
|
bx
|
||||||
}
|
}
|
||||||
mir::StatementKind::FakeRead(..) |
|
mir::StatementKind::FakeRead(..) |
|
||||||
mir::StatementKind::EndRegion(..) |
|
|
||||||
mir::StatementKind::Retag { .. } |
|
mir::StatementKind::Retag { .. } |
|
||||||
mir::StatementKind::EscapeToRaw { .. } |
|
mir::StatementKind::EscapeToRaw { .. } |
|
||||||
mir::StatementKind::AscribeUserType(..) |
|
mir::StatementKind::AscribeUserType(..) |
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use borrow_check::place_ext::PlaceExt;
|
use borrow_check::place_ext::PlaceExt;
|
||||||
|
use borrow_check::nll::ToRegionVid;
|
||||||
use dataflow::indexes::BorrowIndex;
|
use dataflow::indexes::BorrowIndex;
|
||||||
use dataflow::move_paths::MoveData;
|
use dataflow::move_paths::MoveData;
|
||||||
use rustc::mir::traversal;
|
use rustc::mir::traversal;
|
||||||
|
@ -16,7 +17,7 @@ use rustc::mir::visit::{
|
||||||
PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext
|
PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext
|
||||||
};
|
};
|
||||||
use rustc::mir::{self, Location, Mir, Place, Local};
|
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::util::nodemap::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc_data_structures::bit_set::BitSet;
|
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
|
/// Every borrow has a region; this maps each such regions back to
|
||||||
/// its borrow-indexes.
|
/// 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
|
/// Map from local to all the borrows on that local
|
||||||
crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
||||||
|
@ -77,7 +78,7 @@ crate struct BorrowData<'tcx> {
|
||||||
/// What kind of borrow this is
|
/// What kind of borrow this is
|
||||||
crate kind: mir::BorrowKind,
|
crate kind: mir::BorrowKind,
|
||||||
/// The region for which this borrow is live
|
/// The region for which this borrow is live
|
||||||
crate region: Region<'tcx>,
|
crate region: RegionVid,
|
||||||
/// Place from which we are borrowing
|
/// Place from which we are borrowing
|
||||||
crate borrowed_place: mir::Place<'tcx>,
|
crate borrowed_place: mir::Place<'tcx>,
|
||||||
/// Place to which the borrow was stored
|
/// Place to which the borrow was stored
|
||||||
|
@ -92,13 +93,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||||
mir::BorrowKind::Unique => "uniq ",
|
mir::BorrowKind::Unique => "uniq ",
|
||||||
mir::BorrowKind::Mut { .. } => "mut ",
|
mir::BorrowKind::Mut { .. } => "mut ",
|
||||||
};
|
};
|
||||||
let region = self.region.to_string();
|
write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
|
||||||
let separator = if !region.is_empty() {
|
|
||||||
" "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
write!(w, "&{}{}{}{:?}", region, separator, kind, self.borrowed_place)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +184,7 @@ struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
|
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
|
||||||
location_map: FxHashMap<Location, BorrowIndex>,
|
location_map: FxHashMap<Location, BorrowIndex>,
|
||||||
activation_map: FxHashMap<Location, Vec<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>>,
|
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
||||||
|
|
||||||
/// When we encounter a 2-phase borrow statement, it will always
|
/// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let region = region.to_region_vid();
|
||||||
|
|
||||||
let borrow = BorrowData {
|
let borrow = BorrowData {
|
||||||
kind,
|
kind,
|
||||||
region,
|
region,
|
||||||
|
@ -230,7 +227,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
|
||||||
let idx = self.idx_vec.push(borrow);
|
let idx = self.idx_vec.push(borrow);
|
||||||
self.location_map.insert(location, idx);
|
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);
|
self.region_map.entry(region).or_default().insert(idx);
|
||||||
if let Some(local) = borrowed_place.root_local() {
|
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];
|
let borrow_data = &self.idx_vec[borrow_index];
|
||||||
assert_eq!(borrow_data.reserve_location, location);
|
assert_eq!(borrow_data.reserve_location, location);
|
||||||
assert_eq!(borrow_data.kind, kind);
|
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);
|
assert_eq!(borrow_data.borrowed_place, *place);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,13 +344,12 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
start_location: Location,
|
start_location: Location,
|
||||||
assigned_place: &mir::Place<'tcx>,
|
assigned_place: &mir::Place<'tcx>,
|
||||||
region: Region<'tcx>,
|
|
||||||
kind: mir::BorrowKind,
|
kind: mir::BorrowKind,
|
||||||
borrow_index: BorrowIndex,
|
borrow_index: BorrowIndex,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?}, {:?})",
|
"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
|
||||||
start_location, assigned_place, region, borrow_index,
|
start_location, assigned_place, borrow_index,
|
||||||
);
|
);
|
||||||
|
|
||||||
if !self.allow_two_phase_borrow(kind) {
|
if !self.allow_two_phase_borrow(kind) {
|
||||||
|
|
|
@ -14,7 +14,6 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::Node;
|
use rustc::hir::Node;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::map::definitions::DefPathData;
|
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
use rustc::lint::builtin::UNUSED_MUT;
|
use rustc::lint::builtin::UNUSED_MUT;
|
||||||
use rustc::middle::borrowck::SignalledError;
|
use rustc::middle::borrowck::SignalledError;
|
||||||
|
@ -162,10 +161,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||||
move_data: move_data,
|
move_data: move_data,
|
||||||
param_env: param_env,
|
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 dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
|
||||||
let mut flow_inits = FlowAtLocation::new(do_dataflow(
|
let mut flow_inits = FlowAtLocation::new(do_dataflow(
|
||||||
|
@ -212,7 +207,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||||
id,
|
id,
|
||||||
&attributes,
|
&attributes,
|
||||||
&dead_unwinds,
|
&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)),
|
|rs, i| DebugFormatted::new(&rs.location(i)),
|
||||||
));
|
));
|
||||||
let flow_uninits = FlowAtLocation::new(do_dataflow(
|
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);
|
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::Nop
|
||||||
| StatementKind::AscribeUserType(..)
|
| StatementKind::AscribeUserType(..)
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
|
|
|
@ -206,7 +206,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
let mir = self.mir;
|
let mir = self.mir;
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
let borrow_region_vid = regioncx.to_region_vid(borrow.region);
|
let borrow_region_vid = borrow.region;
|
||||||
debug!(
|
debug!(
|
||||||
"explain_why_borrow_contains_point: borrow_region_vid={:?}",
|
"explain_why_borrow_contains_point: borrow_region_vid={:?}",
|
||||||
borrow_region_vid
|
borrow_region_vid
|
||||||
|
|
|
@ -132,8 +132,6 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
||||||
self.consume_operand(context, input);
|
self.consume_operand(context, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL
|
|
||||||
StatementKind::EndRegion(..) |
|
|
||||||
StatementKind::Nop |
|
StatementKind::Nop |
|
||||||
StatementKind::AscribeUserType(..) |
|
StatementKind::AscribeUserType(..) |
|
||||||
StatementKind::Retag { .. } |
|
StatementKind::Retag { .. } |
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
|
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::mir::visit::{MutVisitor, TyContext};
|
||||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
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);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1314,7 +1314,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
| StatementKind::StorageLive(..)
|
| StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
| StatementKind::InlineAsm { .. }
|
| StatementKind::InlineAsm { .. }
|
||||||
| StatementKind::EndRegion(_)
|
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
| StatementKind::EscapeToRaw { .. }
|
| StatementKind::EscapeToRaw { .. }
|
||||||
| StatementKind::Nop => {}
|
| StatementKind::Nop => {}
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
//! Routines for manipulating the control-flow graph.
|
//! Routines for manipulating the control-flow graph.
|
||||||
|
|
||||||
use build::CFG;
|
use build::CFG;
|
||||||
use rustc::middle::region;
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::ty::TyCtxt;
|
|
||||||
|
|
||||||
impl<'tcx> CFG<'tcx> {
|
impl<'tcx> CFG<'tcx> {
|
||||||
pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'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);
|
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,
|
pub fn push_assign(&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
|
|
|
@ -90,12 +90,13 @@ should go to.
|
||||||
use build::{BlockAnd, BlockAndExtension, Builder, CFG};
|
use build::{BlockAnd, BlockAndExtension, Builder, CFG};
|
||||||
use hair::LintLevel;
|
use hair::LintLevel;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty::{Ty, TyCtxt};
|
use rustc::ty::Ty;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::LOCAL_CRATE;
|
use rustc::hir::def_id::LOCAL_CRATE;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use syntax_pos::{Span};
|
use syntax_pos::{Span};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Scope<'tcx> {
|
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
|
/// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
|
||||||
/// larger extent of code.
|
/// 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
|
/// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
|
||||||
/// top-of-scope (as opposed to dependent scopes).
|
/// top-of-scope (as opposed to dependent scopes).
|
||||||
fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) {
|
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 {
|
if !storage_only && !this_scope_only {
|
||||||
for dropdata in &mut self.drops {
|
for drop_data in &mut self.drops {
|
||||||
if let DropKind::Value { ref mut cached_block } = dropdata.kind {
|
if let DropKind::Value { ref mut cached_block } = drop_data.kind {
|
||||||
cached_block.invalidate();
|
cached_block.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +324,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let parent_hir_id =
|
let parent_hir_id =
|
||||||
tcx.hir.definitions().node_to_hir_id(
|
tcx.hir.definitions().node_to_hir_id(
|
||||||
self.source_scope_local_data[source_scope].lint_root
|
self.source_scope_local_data[source_scope].lint_root
|
||||||
);
|
);
|
||||||
let current_hir_id =
|
let current_hir_id =
|
||||||
tcx.hir.definitions().node_to_hir_id(node_id);
|
tcx.hir.definitions().node_to_hir_id(node_id);
|
||||||
sets.lint_level_set(parent_hir_id) ==
|
sets.lint_level_set(parent_hir_id) ==
|
||||||
|
@ -333,7 +334,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
if !same_lint_scopes {
|
if !same_lint_scopes {
|
||||||
self.source_scope =
|
self.source_scope =
|
||||||
self.new_source_scope(region_scope.1.span, lint_level,
|
self.new_source_scope(region_scope.1.span, lint_level,
|
||||||
None);
|
None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.push_scope(region_scope);
|
self.push_scope(region_scope);
|
||||||
|
@ -381,15 +382,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let scope = self.scopes.pop().unwrap();
|
let scope = self.scopes.pop().unwrap();
|
||||||
assert_eq!(scope.region_scope, region_scope.0);
|
assert_eq!(scope.region_scope, region_scope.0);
|
||||||
|
|
||||||
self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
|
let unwind_to = self.scopes.last().and_then(|next_scope| {
|
||||||
let resume_block = self.resume_block();
|
next_scope.cached_unwind.get(false)
|
||||||
unpack!(block = build_scope_drops(&mut self.cfg,
|
}).unwrap_or_else(|| self.resume_block());
|
||||||
resume_block,
|
|
||||||
&scope,
|
unpack!(block = build_scope_drops(
|
||||||
&self.scopes,
|
&mut self.cfg,
|
||||||
block,
|
&scope,
|
||||||
self.arg_count,
|
block,
|
||||||
false));
|
unwind_to,
|
||||||
|
self.arg_count,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
block.unit()
|
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
|
/// Branch out of `block` to `target`, exiting all scopes up to
|
||||||
/// and including `region_scope`. This will insert whatever drops are
|
/// and including `region_scope`. This will insert whatever drops are
|
||||||
/// needed, as well as tracking this exit for the SEME region. See
|
/// needed. See module comment for details.
|
||||||
/// module comment for details.
|
|
||||||
pub fn exit_scope(&mut self,
|
pub fn exit_scope(&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
region_scope: (region::Scope, SourceInfo),
|
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
|
// If we are emitting a `drop` statement, we need to have the cached
|
||||||
// diverge cleanup pads ready in case that drop panics.
|
// diverge cleanup pads ready in case that drop panics.
|
||||||
let may_panic = self.scopes[(len - scope_count)..].iter()
|
let may_panic = self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup);
|
||||||
.any(|s| s.drops.iter().any(|s| s.kind.may_panic()));
|
|
||||||
if may_panic {
|
if may_panic {
|
||||||
self.diverge_cleanup();
|
self.diverge_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let mut scopes = self.scopes[(len - scope_count - 1)..].iter_mut().rev();
|
||||||
let resume_block = self.resume_block();
|
let mut scope = scopes.next().unwrap();
|
||||||
let mut rest = &mut self.scopes[(len - scope_count)..];
|
for next_scope in scopes {
|
||||||
while let Some((scope, rest_)) = {rest}.split_last_mut() {
|
if scope.drops.is_empty() {
|
||||||
rest = rest_;
|
scope = next_scope;
|
||||||
block = if let Some(&e) = scope.cached_exits.get(&(target, region_scope.0)) {
|
continue;
|
||||||
self.cfg.terminate(block, scope.source_info(span),
|
}
|
||||||
TerminatorKind::Goto { target: e });
|
let source_info = scope.source_info(span);
|
||||||
return;
|
block = match scope.cached_exits.entry((target, region_scope.0)) {
|
||||||
} else {
|
Entry::Occupied(e) => {
|
||||||
let b = self.cfg.start_new_block();
|
self.cfg.terminate(block, source_info,
|
||||||
self.cfg.terminate(block, scope.source_info(span),
|
TerminatorKind::Goto { target: *e.get() });
|
||||||
TerminatorKind::Goto { target: b });
|
return;
|
||||||
scope.cached_exits.insert((target, region_scope.0), b);
|
}
|
||||||
b
|
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.
|
let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
|
||||||
self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
|
debug_assert!(!may_panic, "cached block not present?");
|
||||||
|
START_BLOCK
|
||||||
|
});
|
||||||
|
|
||||||
unpack!(block = build_scope_drops(&mut self.cfg,
|
unpack!(block = build_scope_drops(
|
||||||
resume_block,
|
&mut self.cfg,
|
||||||
scope,
|
scope,
|
||||||
rest,
|
block,
|
||||||
block,
|
unwind_to,
|
||||||
self.arg_count,
|
self.arg_count,
|
||||||
false));
|
false,
|
||||||
}
|
));
|
||||||
|
|
||||||
|
scope = next_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scope = &self.scopes[len - scope_count];
|
let scope = &self.scopes[len - scope_count];
|
||||||
self.cfg.terminate(block, scope.source_info(span),
|
self.cfg.terminate(block, scope.source_info(span),
|
||||||
TerminatorKind::Goto { target });
|
TerminatorKind::Goto { target });
|
||||||
|
@ -465,20 +478,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the cache
|
// Fill in the cache for unwinds
|
||||||
self.diverge_cleanup_gen(true);
|
self.diverge_cleanup_gen(true);
|
||||||
|
|
||||||
let src_info = self.scopes[0].source_info(self.fn_span);
|
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 mut block = self.cfg.start_new_block();
|
||||||
let result = 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() {
|
while let Some(scope) = scopes.next() {
|
||||||
rest = rest_;
|
|
||||||
if !scope.needs_cleanup {
|
if !scope.needs_cleanup {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
block = if let Some(b) = scope.cached_generator_drop {
|
block = if let Some(b) = scope.cached_generator_drop {
|
||||||
self.cfg.terminate(block, src_info,
|
self.cfg.terminate(block, src_info,
|
||||||
TerminatorKind::Goto { target: b });
|
TerminatorKind::Goto { target: b });
|
||||||
|
@ -491,16 +504,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
b
|
b
|
||||||
};
|
};
|
||||||
|
|
||||||
// End all regions for scopes out of which we are breaking.
|
let unwind_to = scopes.peek().as_ref().map(|scope| {
|
||||||
self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_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,
|
unpack!(block = build_scope_drops(
|
||||||
resume_block,
|
&mut self.cfg,
|
||||||
scope,
|
scope,
|
||||||
rest,
|
block,
|
||||||
block,
|
unwind_to,
|
||||||
self.arg_count,
|
self.arg_count,
|
||||||
true));
|
true,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
|
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.
|
/// Creates a new source scope, nested in the current one.
|
||||||
pub fn new_source_scope(&mut self,
|
pub fn new_source_scope(&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
lint_level: LintLevel,
|
lint_level: LintLevel,
|
||||||
safety: Option<Safety>) -> SourceScope {
|
safety: Option<Safety>) -> SourceScope {
|
||||||
let parent = self.source_scope;
|
let parent = self.source_scope;
|
||||||
debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
|
debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
|
||||||
span, lint_level, safety,
|
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.
|
/// Creates a path that performs all required cleanup for unwinding.
|
||||||
///
|
///
|
||||||
/// This path terminates in Resume. Returns the start of the path.
|
/// This path terminates in Resume. Returns the start of the path.
|
||||||
/// See module comment for more details. None indicates there’s no
|
/// See module comment for more details.
|
||||||
/// cleanup to do at this point.
|
|
||||||
pub fn diverge_cleanup(&mut self) -> BasicBlock {
|
pub fn diverge_cleanup(&mut self) -> BasicBlock {
|
||||||
self.diverge_cleanup_gen(false)
|
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 {
|
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
|
// Build up the drops in **reverse** order. The end result will
|
||||||
// look like:
|
// 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
|
// store caches. If everything is cached, we'll just walk right
|
||||||
// to left reading the cached results but never created anything.
|
// to left reading the cached results but never created anything.
|
||||||
|
|
||||||
if scopes.iter().any(|scope| scope.needs_cleanup) {
|
// Find the last cached block
|
||||||
for scope in scopes.iter_mut() {
|
let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter()
|
||||||
target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
|
.rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) {
|
||||||
scope, target, generator_drop);
|
(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
|
target
|
||||||
|
@ -866,64 +883,62 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds drops for pop_scope and exit_scope.
|
/// Builds drops for pop_scope and exit_scope.
|
||||||
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
fn build_scope_drops<'tcx>(
|
||||||
resume_block: BasicBlock,
|
cfg: &mut CFG<'tcx>,
|
||||||
scope: &Scope<'tcx>,
|
scope: &Scope<'tcx>,
|
||||||
earlier_scopes: &[Scope<'tcx>],
|
mut block: BasicBlock,
|
||||||
mut block: BasicBlock,
|
last_unwind_to: BasicBlock,
|
||||||
arg_count: usize,
|
arg_count: usize,
|
||||||
generator_drop: bool)
|
generator_drop: bool,
|
||||||
-> BlockAnd<()> {
|
) -> BlockAnd<()> {
|
||||||
debug!("build_scope_drops({:?} -> {:?})", block, scope);
|
debug!("build_scope_drops({:?} -> {:?}", block, scope);
|
||||||
let mut iter = scope.drops.iter().rev();
|
|
||||||
while let Some(drop_data) = iter.next() {
|
// 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);
|
let source_info = scope.source_info(drop_data.span);
|
||||||
match drop_data.kind {
|
match drop_data.kind {
|
||||||
DropKind::Value { .. } => {
|
DropKind::Value { .. } => {
|
||||||
// Try to find the next block with its cached block for us to
|
let unwind_to = unwind_blocks.next().unwrap_or(last_unwind_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 next = cfg.start_new_block();
|
let next = cfg.start_new_block();
|
||||||
cfg.terminate(block, source_info, TerminatorKind::Drop {
|
cfg.terminate(block, source_info, TerminatorKind::Drop {
|
||||||
location: drop_data.location.clone(),
|
location: drop_data.location.clone(),
|
||||||
target: next,
|
target: next,
|
||||||
unwind: Some(on_diverge.unwrap_or(resume_block))
|
unwind: Some(unwind_to)
|
||||||
});
|
});
|
||||||
block = next;
|
block = next;
|
||||||
}
|
}
|
||||||
|
@ -950,21 +965,17 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
||||||
block.unit()
|
block.unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
|
||||||
cfg: &mut CFG<'tcx>,
|
span: Span,
|
||||||
span: Span,
|
scope: &mut Scope<'tcx>,
|
||||||
scope: &mut Scope<'tcx>,
|
mut target: BasicBlock,
|
||||||
mut target: BasicBlock,
|
generator_drop: bool)
|
||||||
generator_drop: bool)
|
-> BasicBlock
|
||||||
-> BasicBlock
|
|
||||||
{
|
{
|
||||||
// Build up the drops in **reverse** order. The end result will
|
// Build up the drops in **reverse** order. The end result will
|
||||||
// look like:
|
// look like:
|
||||||
//
|
//
|
||||||
// [EndRegion Block] -> [drops[n]] -...-> [drops[0]] -> [Free] -> [target]
|
// [drops[n]] -...-> [drops[0]] -> [target]
|
||||||
// | |
|
|
||||||
// +---------------------------------------------------------+
|
|
||||||
// code for scope
|
|
||||||
//
|
//
|
||||||
// The code in this function reads from right to left. At each
|
// The code in this function reads from right to left. At each
|
||||||
// point, we check for cached blocks representing the
|
// 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
|
*scope.cached_unwind.ref_mut(generator_drop) = Some(target);
|
||||||
// `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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
|
debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
|
||||||
|
|
||||||
|
|
|
@ -12,18 +12,13 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData};
|
||||||
use borrow_check::place_ext::PlaceExt;
|
use borrow_check::place_ext::PlaceExt;
|
||||||
|
|
||||||
use rustc;
|
use rustc;
|
||||||
use rustc::hir;
|
|
||||||
use rustc::hir::def_id::DefId;
|
|
||||||
use rustc::middle::region;
|
|
||||||
use rustc::mir::{self, Location, Place, Mir};
|
use rustc::mir::{self, Location, Place, Mir};
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::ty::{RegionKind, RegionVid};
|
use rustc::ty::RegionVid;
|
||||||
use rustc::ty::RegionKind::ReScope;
|
|
||||||
|
|
||||||
use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
|
use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
use rustc_data_structures::sync::Lrc;
|
|
||||||
|
|
||||||
use dataflow::{BitDenotation, BlockSets, InitialFlow};
|
use dataflow::{BitDenotation, BlockSets, InitialFlow};
|
||||||
pub use dataflow::indexes::BorrowIndex;
|
pub use dataflow::indexes::BorrowIndex;
|
||||||
|
@ -42,8 +37,6 @@ use std::rc::Rc;
|
||||||
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
mir: &'a Mir<'tcx>,
|
mir: &'a Mir<'tcx>,
|
||||||
scope_tree: Lrc<region::ScopeTree>,
|
|
||||||
root_scope: Option<region::Scope>,
|
|
||||||
|
|
||||||
borrow_set: Rc<BorrowSet<'tcx>>,
|
borrow_set: Rc<BorrowSet<'tcx>>,
|
||||||
borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
|
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>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
mir: &'a Mir<'tcx>,
|
mir: &'a Mir<'tcx>,
|
||||||
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
|
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||||
def_id: DefId,
|
|
||||||
body_id: Option<hir::BodyId>,
|
|
||||||
borrow_set: &Rc<BorrowSet<'tcx>>,
|
borrow_set: &Rc<BorrowSet<'tcx>>,
|
||||||
) -> Self {
|
) -> 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();
|
let mut borrows_out_of_scope_at_location = FxHashMap::default();
|
||||||
for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() {
|
for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() {
|
||||||
let borrow_region = borrow_data.region.to_region_vid();
|
let borrow_region = borrow_data.region.to_region_vid();
|
||||||
|
@ -177,8 +160,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
||||||
mir: mir,
|
mir: mir,
|
||||||
borrow_set: borrow_set.clone(),
|
borrow_set: borrow_set.clone(),
|
||||||
borrows_out_of_scope_at_location,
|
borrows_out_of_scope_at_location,
|
||||||
scope_tree,
|
|
||||||
root_scope,
|
|
||||||
_nonlexical_regioncx: nonlexical_regioncx,
|
_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`.
|
/// 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
|
/// That means they went out of a nonlexical scope
|
||||||
/// at the moment, or the location represents a lexical EndRegion
|
|
||||||
fn kill_loans_out_of_scope_at_location(&self,
|
fn kill_loans_out_of_scope_at_location(&self,
|
||||||
sets: &mut BlockSets<BorrowIndex>,
|
sets: &mut BlockSets<BorrowIndex>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
|
@ -252,9 +232,6 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||||
});
|
});
|
||||||
|
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
mir::StatementKind::EndRegion(_) => {
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::StatementKind::Assign(ref lhs, ref rhs) => {
|
mir::StatementKind::Assign(ref lhs, ref rhs) => {
|
||||||
// Make sure there are no remaining borrows for variables
|
// Make sure there are no remaining borrows for variables
|
||||||
// that are assigned over.
|
// 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);
|
panic!("could not find BorrowIndex for location {:?}", location);
|
||||||
});
|
});
|
||||||
|
|
||||||
if let RegionKind::ReEmpty = region {
|
assert!(self.borrow_set.region_map
|
||||||
// If the borrowed value dies before the borrow is used, the region for
|
.get(®ion.to_region_vid())
|
||||||
// the borrow can be empty. Don't track the borrow in that case.
|
.unwrap_or_else(|| {
|
||||||
debug!("Borrows::statement_effect_on_borrows \
|
panic!("could not find BorrowIndexs for RegionVid {:?}", region);
|
||||||
location: {:?} stmt: {:?} has empty region, killing {:?}",
|
})
|
||||||
location, stmt.kind, index);
|
.contains(&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));
|
|
||||||
sets.gen(*index);
|
sets.gen(*index);
|
||||||
|
|
||||||
// Issue #46746: Two-phase borrows handles
|
// 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);
|
self.kill_loans_out_of_scope_at_location(sets, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminator_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
|
fn terminator_effect(&self, _: &mut BlockSets<BorrowIndex>, _: 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 propagate_call_return(&self,
|
fn propagate_call_return(&self,
|
||||||
_in_out: &mut BitSet<BorrowIndex>,
|
_in_out: &mut BitSet<BorrowIndex>,
|
||||||
|
|
|
@ -301,7 +301,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||||
span_bug!(stmt.source_info.span,
|
span_bug!(stmt.source_info.span,
|
||||||
"SetDiscriminant should not exist during borrowck");
|
"SetDiscriminant should not exist during borrowck");
|
||||||
}
|
}
|
||||||
StatementKind::EndRegion(..) |
|
|
||||||
StatementKind::Retag { .. } |
|
StatementKind::Retag { .. } |
|
||||||
StatementKind::EscapeToRaw { .. } |
|
StatementKind::EscapeToRaw { .. } |
|
||||||
StatementKind::AscribeUserType(..) |
|
StatementKind::AscribeUserType(..) |
|
||||||
|
|
|
@ -129,7 +129,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statements we do not track.
|
// Statements we do not track.
|
||||||
EndRegion(..) => {}
|
|
||||||
AscribeUserType(..) => {}
|
AscribeUserType(..) => {}
|
||||||
|
|
||||||
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||||
|
|
|
@ -112,7 +112,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||||
StatementKind::SetDiscriminant { .. } |
|
StatementKind::SetDiscriminant { .. } |
|
||||||
StatementKind::StorageLive(..) |
|
StatementKind::StorageLive(..) |
|
||||||
StatementKind::StorageDead(..) |
|
StatementKind::StorageDead(..) |
|
||||||
StatementKind::EndRegion(..) |
|
|
||||||
StatementKind::Retag { .. } |
|
StatementKind::Retag { .. } |
|
||||||
StatementKind::EscapeToRaw { .. } |
|
StatementKind::EscapeToRaw { .. } |
|
||||||
StatementKind::AscribeUserType(..) |
|
StatementKind::AscribeUserType(..) |
|
||||||
|
|
|
@ -10,111 +10,26 @@
|
||||||
|
|
||||||
//! This module provides two passes:
|
//! This module provides two passes:
|
||||||
//!
|
//!
|
||||||
//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements
|
//! - [CleanAscribeUserType], that replaces all
|
||||||
//! in the MIR.
|
//! [StatementKind::AscribeUserType] statements with [StatementKind::Nop].
|
||||||
//! - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements
|
//! - [CleanFakeReadsAndBorrows], that replaces all [FakeRead] statements and
|
||||||
//! with `Nop`.
|
//! 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,
|
//! traversals (aka visits) of the input MIR. The first traversal,
|
||||||
//! `GatherBorrowedRegions`, finds all of the regions in the MIR
|
//! [DeleteAndRecordFakeReads], deletes the fake reads and finds the temporaries
|
||||||
//! that are involved in a borrow.
|
//! read by [ForMatchGuard] reads, and [DeleteFakeBorrows] deletes the
|
||||||
//!
|
//! initialization of those temporaries.
|
||||||
//! 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.
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
||||||
use rustc::middle::region;
|
|
||||||
use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place};
|
use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place};
|
||||||
use rustc::mir::{Rvalue, Statement, StatementKind};
|
use rustc::mir::{Statement, StatementKind};
|
||||||
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::ty::{Ty, RegionKind, TyCtxt};
|
use rustc::ty::TyCtxt;
|
||||||
use smallvec::smallvec;
|
|
||||||
use transform::{MirPass, MirSource};
|
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 CleanAscribeUserType;
|
||||||
|
|
||||||
pub struct DeleteAscribeUserType;
|
pub struct DeleteAscribeUserType;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//! We want to do this once just before codegen, so codegen does not have to take
|
//! We want to do this once just before codegen, so codegen does not have to take
|
||||||
//! care erasing regions all over the place.
|
//! care erasing regions all over the place.
|
||||||
//! NOTE: We do NOT erase regions of statements that are relevant for
|
//! 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::subst::Substs;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
@ -54,10 +54,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
statement: &mut Statement<'tcx>,
|
statement: &mut Statement<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let StatementKind::EndRegion(_) = statement.kind {
|
|
||||||
statement.kind = StatementKind::Nop;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.super_statement(block, statement, location);
|
self.super_statement(block, statement, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
let mut mir = tcx.mir_built(def_id).steal();
|
||||||
run_passes(tcx, &mut mir, def_id, MirPhase::Const, &[
|
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.
|
// What we need to do constant evaluation.
|
||||||
&simplify::SimplifyCfg::new("initial"),
|
&simplify::SimplifyCfg::new("initial"),
|
||||||
&type_check::TypeckMir,
|
&type_check::TypeckMir,
|
||||||
|
|
|
@ -1168,7 +1168,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
StatementKind::StorageLive(_) |
|
StatementKind::StorageLive(_) |
|
||||||
StatementKind::StorageDead(_) |
|
StatementKind::StorageDead(_) |
|
||||||
StatementKind::InlineAsm {..} |
|
StatementKind::InlineAsm {..} |
|
||||||
StatementKind::EndRegion(_) |
|
|
||||||
StatementKind::Retag { .. } |
|
StatementKind::Retag { .. } |
|
||||||
StatementKind::EscapeToRaw { .. } |
|
StatementKind::EscapeToRaw { .. } |
|
||||||
StatementKind::AscribeUserType(..) |
|
StatementKind::AscribeUserType(..) |
|
||||||
|
|
|
@ -243,7 +243,6 @@ fn check_statement(
|
||||||
| StatementKind::StorageDead(_)
|
| StatementKind::StorageDead(_)
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
| StatementKind::EscapeToRaw { .. }
|
| StatementKind::EscapeToRaw { .. }
|
||||||
| StatementKind::EndRegion(_)
|
|
||||||
| StatementKind::AscribeUserType(..)
|
| StatementKind::AscribeUserType(..)
|
||||||
| StatementKind::Nop => Ok(()),
|
| StatementKind::Nop => Ok(()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,12 +52,9 @@ impl RemoveNoopLandingPads {
|
||||||
StatementKind::FakeRead(..) |
|
StatementKind::FakeRead(..) |
|
||||||
StatementKind::StorageLive(_) |
|
StatementKind::StorageLive(_) |
|
||||||
StatementKind::StorageDead(_) |
|
StatementKind::StorageDead(_) |
|
||||||
StatementKind::EndRegion(_) |
|
|
||||||
StatementKind::AscribeUserType(..) |
|
StatementKind::AscribeUserType(..) |
|
||||||
StatementKind::Nop => {
|
StatementKind::Nop => {
|
||||||
// These are all nops in a landing pad (there's some
|
// These are all nops in a landing pad
|
||||||
// borrowck interaction between EndRegion and storage
|
|
||||||
// instructions, but this should all run after borrowck).
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => {
|
StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => {
|
||||||
|
|
|
@ -161,7 +161,6 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
mir::StatementKind::StorageLive(_) |
|
mir::StatementKind::StorageLive(_) |
|
||||||
mir::StatementKind::StorageDead(_) |
|
mir::StatementKind::StorageDead(_) |
|
||||||
mir::StatementKind::InlineAsm { .. } |
|
mir::StatementKind::InlineAsm { .. } |
|
||||||
mir::StatementKind::EndRegion(_) |
|
|
||||||
mir::StatementKind::Retag { .. } |
|
mir::StatementKind::Retag { .. } |
|
||||||
mir::StatementKind::EscapeToRaw { .. } |
|
mir::StatementKind::EscapeToRaw { .. } |
|
||||||
mir::StatementKind::AscribeUserType(..) |
|
mir::StatementKind::AscribeUserType(..) |
|
||||||
|
|
|
@ -83,7 +83,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||||
self.record(match statement.kind {
|
self.record(match statement.kind {
|
||||||
StatementKind::Assign(..) => "StatementKind::Assign",
|
StatementKind::Assign(..) => "StatementKind::Assign",
|
||||||
StatementKind::FakeRead(..) => "StatementKind::FakeRead",
|
StatementKind::FakeRead(..) => "StatementKind::FakeRead",
|
||||||
StatementKind::EndRegion(..) => "StatementKind::EndRegion",
|
|
||||||
StatementKind::Retag { .. } => "StatementKind::Retag",
|
StatementKind::Retag { .. } => "StatementKind::Retag",
|
||||||
StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw",
|
StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw",
|
||||||
StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant",
|
StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant",
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -44,7 +44,7 @@ fn main() {
|
||||||
// falseUnwind -> [real: bb3, cleanup: bb4];
|
// falseUnwind -> [real: bb3, cleanup: bb4];
|
||||||
// }
|
// }
|
||||||
// bb2: {
|
// bb2: {
|
||||||
// goto -> bb29;
|
// goto -> bb20;
|
||||||
// }
|
// }
|
||||||
// bb3: {
|
// bb3: {
|
||||||
// StorageLive(_2);
|
// StorageLive(_2);
|
||||||
|
@ -90,58 +90,31 @@ fn main() {
|
||||||
// StorageDead(_3);
|
// StorageDead(_3);
|
||||||
// StorageLive(_6);
|
// StorageLive(_6);
|
||||||
// _6 = &_2;
|
// _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: {
|
// bb15: {
|
||||||
|
// StorageDead(_3);
|
||||||
// goto -> bb16;
|
// goto -> bb16;
|
||||||
// }
|
// }
|
||||||
// bb16: {
|
// bb16: {
|
||||||
// goto -> bb17;
|
|
||||||
// }
|
|
||||||
// bb17: {
|
|
||||||
// goto -> bb18;
|
|
||||||
// }
|
|
||||||
// bb18: {
|
|
||||||
// goto -> bb19;
|
|
||||||
// }
|
|
||||||
// bb19: {
|
|
||||||
// goto -> bb20;
|
|
||||||
// }
|
|
||||||
// bb20: {
|
|
||||||
// StorageDead(_3);
|
|
||||||
// goto -> bb21;
|
|
||||||
// }
|
|
||||||
// bb21: {
|
|
||||||
// goto -> bb22;
|
|
||||||
// }
|
|
||||||
// bb22: {
|
|
||||||
// StorageDead(_2);
|
// StorageDead(_2);
|
||||||
// goto -> bb23;
|
|
||||||
// }
|
|
||||||
// bb23: {
|
|
||||||
// goto -> bb24;
|
|
||||||
// }
|
|
||||||
// bb24: {
|
|
||||||
// goto -> bb25;
|
|
||||||
// }
|
|
||||||
// bb25: {
|
|
||||||
// goto -> bb2;
|
// goto -> bb2;
|
||||||
// }
|
// }
|
||||||
// bb26: {
|
// bb17: {
|
||||||
// _4 = ();
|
// _4 = ();
|
||||||
// unreachable;
|
// unreachable;
|
||||||
// }
|
// }
|
||||||
// bb27: {
|
// bb18: {
|
||||||
// StorageDead(_4);
|
// StorageDead(_4);
|
||||||
// goto -> bb14;
|
// goto -> bb14;
|
||||||
// }
|
// }
|
||||||
// bb28: {
|
// bb19: {
|
||||||
// StorageDead(_6);
|
// StorageDead(_6);
|
||||||
// _1 = ();
|
// _1 = ();
|
||||||
// StorageDead(_2);
|
// StorageDead(_2);
|
||||||
// goto -> bb1;
|
// goto -> bb1;
|
||||||
// }
|
// }
|
||||||
// bb29: {
|
// bb20: {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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
|
// Tests to make sure we correctly generate falseUnwind edges in loops
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// run-pass
|
// run-pass
|
||||||
//compile-flags: -Z borrowck=compare -Z emit-end-regions
|
//compile-flags: -Z borrowck=compare
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//compile-flags: -Z emit-end-regions -Z borrowck=compare
|
//compile-flags: -Z borrowck=compare
|
||||||
|
|
||||||
fn foo(_x: u32) {
|
fn foo(_x: u32) {
|
||||||
_x = 4;
|
_x = 4;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// Test that assignments to an `&mut` pointer which is found in a
|
// Test that assignments to an `&mut` pointer which is found in a
|
||||||
// borrowed (but otherwise non-aliasable) location is illegal.
|
// 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> {
|
struct S<'a> {
|
||||||
pointer: &'a mut isize
|
pointer: &'a mut isize
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// Test that assignments to an `&mut` pointer which is found in a
|
// Test that assignments to an `&mut` pointer which is found in a
|
||||||
// borrowed (but otherwise non-aliasable) location is illegal.
|
// 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> {
|
struct S<'a> {
|
||||||
pointer: &'a mut isize
|
pointer: &'a mut isize
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// revisions: ast mir
|
// revisions: ast mir
|
||||||
//[mir]compile-flags: -Z emit-end-regions -Z borrowck=mir
|
//[mir]compile-flags: -Z borrowck=mir
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = 0;
|
let x = 0;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z emit-end-regions -Z borrowck=compare
|
// compile-flags: -Z borrowck=compare
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let y = {
|
let y = {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z emit-end-regions -Z borrowck=compare
|
// compile-flags: -Z borrowck=compare
|
||||||
|
|
||||||
fn foo() -> &'static u32 {
|
fn foo() -> &'static u32 {
|
||||||
let x = 0;
|
let x = 0;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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 {
|
fn bar<'a>() -> &'a mut u32 {
|
||||||
&mut 4
|
&mut 4
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#![feature(box_syntax)]
|
#![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>)> {
|
fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
|
||||||
box (x, x)
|
box (x, x)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z emit-end-regions -Zborrowck=mir
|
// compile-flags: -Zborrowck=mir
|
||||||
// compile-pass
|
// compile-pass
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir
|
//compile-flags: -Zborrowck=mir
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir
|
//compile-flags: -Zborrowck=mir
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir
|
//compile-flags: -Zborrowck=mir
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue