}
}
+#[macro_export]
+macro_rules! read_only {
+ ($body_cache:expr) => {
+ {
+ $body_cache.ensure_predecessors();
+ $body_cache.unwrap_read_only()
+ }
+ };
+}
+
impl BodyCache<'tcx> {
pub fn ensure_predecessors(&mut self) {
self.cache.ensure_predecessors(&self.body);
self.cache.predecessors(&self.body)
}
- pub fn read_only(&self) -> ReadOnlyBodyCache<'_, '_> {
- assert!(self.cache.predecessors.is_some(), "");
- ReadOnlyBodyCache {
- cache: &self.cache,
- body: &self.body,
- }
+ pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> {
+ ReadOnlyBodyCache::new(&self.cache, &self.body)
}
pub fn body(&self) -> &Body<'tcx> {
&mut self.body
}
+ pub fn cache(&self) -> &Cache { &self.cache }
+
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
self.cache.basic_blocks_mut(&mut self.body)
}
}
impl ReadOnlyBodyCache<'a, 'tcx> {
+ fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self {
+ assert!(
+ cache.predecessors.is_some(),
+ "Cannot construct ReadOnlyBodyCache without computed predecessors");
+ Self {
+ cache,
+ body,
+ }
+ }
+
+ pub fn from_external_cache(cache: &'a mut Cache, body: &'a Body<'tcx>) -> Self {
+ cache.ensure_predecessors(body);
+ Self {
+ cache,
+ body,
+ }
+ }
+
#[inline]
pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
self.cache.predecessors.as_ref().unwrap()
use syntax_pos::{Span, DUMMY_SP};
pub use crate::mir::interpret::AssertMessage;
-pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
+// TODO(nashenas88) Cache only exported for use in librustc_mir/transform/check_unsafety.rs
+pub use crate::mir::cache::{BodyCache, Cache, ReadOnlyBodyCache};
+pub use crate::read_only;
pub mod cache;
pub mod interpret;
crate::mir::Promoted,
crate::mir::BodyCache<'tcx>
>> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
- promoted.map(|p| &*tcx.arena.alloc(p))
+ promoted.map(|p| {
+ let cache = tcx.arena.alloc(p);
+ for body_cache in cache.iter_mut() {
+ body_cache.ensure_predecessors();
+ }
+ &*cache
+ })
}
}
}
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyCache<'tcx, 'tcx> {
match instance {
ty::InstanceDef::Item(did) => {
- self.optimized_mir(did).read_only()
+ self.optimized_mir(did).unwrap_read_only()
}
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::DropGlue(..) |
ty::InstanceDef::CloneShim(..) => {
- self.mir_shims(instance).read_only()
+ self.mir_shims(instance).unwrap_read_only()
}
}
}
}
fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyCache<'tcx> {
- self.root.per_def.mir.get(self, id)
+ let mut cache = self.root.per_def.mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id))
})
- .decode((self, tcx))
+ .decode((self, tcx));
+ cache.ensure_predecessors();
+ cache
}
fn get_promoted_mir(
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> IndexVec<Promoted, BodyCache<'tcx>> {
- self.root.per_def.promoted_mir.get(self, id)
+ let mut cache = self.root.per_def.promoted_mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id))
})
- .decode((self, tcx))
+ .decode((self, tcx));
+ for body_cache in cache.iter_mut() {
+ body_cache.ensure_predecessors();
+ }
+ cache
}
fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{
ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase,
- PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind
+ PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind, read_only
};
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
let mut body_cache = BodyCache::new(body);
let free_regions =
nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body_cache, &mut promoted);
- let body_cache = body_cache.read_only(); // no further changes
- let promoted: IndexVec<_, _> = promoted.iter().map(|body_cache| body_cache.read_only()).collect();
+ let body_cache = read_only!(body_cache); // no further changes
+ let promoted: IndexVec<_, _> = promoted.iter_mut().map(|body_cache| read_only!(body_cache)).collect();
let location_table = &LocationTable::new(&body_cache);
type FlowState = Flows<'cx, 'tcx>;
fn body(&self) -> &'cx Body<'tcx> {
- &self.body_cache
+ self.body_cache.body()
}
fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
}
}
- for &pred_block in self.cx.body_cache.predecessors_for(block).iter() {
+ let body_cache = self.cx.body_cache;
+ for &pred_block in body_cache.predecessors_for(block).iter() {
debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
// Check whether the variable is (at least partially)
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
- let parent_body = mem::replace(&mut self.body, &promoted_body_cache);
+ let parent_body = mem::replace(&mut self.body, promoted_body_cache.body());
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
Prefixes {
next: Some(place_ref),
kind,
- body: &self.body_cache,
+ body: self.body_cache.body(),
tcx: self.infcx.tcx,
}
}
}
trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
if let Some(promoted) = promoted {
- return Ok(self.tcx.promoted_mir(did)[promoted].read_only());
+ return Ok(self.tcx.promoted_mir(did)[promoted].unwrap_read_only());
}
match instance {
ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) {
- Ok(self.tcx.optimized_mir(did).read_only())
+ Ok(self.tcx.optimized_mir(did).unwrap_read_only())
} else {
throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id)))
},
debug!("make_shim({:?}) = {:?}", instance, result.body());
+ result.ensure_predecessors();
tcx.arena.alloc(result)
}
|_, _| Ok(()),
);
- tcx.arena.alloc(BodyCache::new(body))
+ let mut body_cache = BodyCache::new(body);
+ body_cache.ensure_predecessors();
+ tcx.arena.alloc(body_cache)
}
// N.B., this borrow is valid because all the consumers of
// `mir_built` force this.
- let body = &tcx.mir_built(def_id).borrow();
+ let body_cache = &tcx.mir_built(def_id).borrow();
let param_env = tcx.param_env(def_id);
hir::BodyOwnerKind::Const |
hir::BodyOwnerKind::Static(_) => (true, false),
};
- let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
- checker.visit_body(body.read_only());
+ let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body_cache, tcx, param_env);
+ let mut cache = body_cache.cache().clone();
+ let read_only_cache = ReadOnlyBodyCache::from_external_cache(&mut cache, body_cache.body());
+ checker.visit_body(read_only_cache);
check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
UnsafetyCheckResult {
AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyCache, Operand, Local, UnOp,
Rvalue. StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate,
SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyCache,
- RETURN_PLACE
+ read_only, RETURN_PLACE
};
use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
// That would require an uniform one-def no-mutation analysis
// and RPO (or recursing when needing the value of a local).
let mut optimization_finder = ConstPropagator::new(
- body_cache.read_only(),
+ read_only!(body_cache),
dummy_body,
tcx,
source
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
- body_cache: ReadOnlyBodyCache<'mir, 'tcx>,
+ body_cache: ReadOnlyBodyCache<'_, 'tcx>,
dummy_body: &'mir Body<'tcx>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
use rustc::mir::{
Constant, Local, LocalKind, Location, Place, Body, BodyCache, Operand, Rvalue,
- StatementKind
+ StatementKind, read_only
};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
let mut def_use_analysis = DefUseAnalysis::new(body_cache);
loop {
- def_use_analysis.analyze(body_cache.read_only());
+ def_use_analysis.analyze(read_only!(body_cache));
if eliminate_self_assignments(body_cache, &def_use_analysis) {
- def_use_analysis.analyze(body_cache.read_only());
+ def_use_analysis.analyze(read_only!(body_cache));
}
let mut changed = false;
// Use a liveness analysis to compute locals which are live across a suspension point
let LivenessInfo {
live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness
- } = locals_live_across_suspend_points(tcx, body_cache.read_only(), source, movable);
+ } = locals_live_across_suspend_points(tcx, read_only!(body_cache), source, movable);
// Erase regions from the types passed in from typeck so we can compare them with
// MIR types
&self,
args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>,
- caller_body: &mut Body<'tcx>,
+ caller_body_cache: &mut BodyCache<'tcx>,
) -> Vec<Local> {
let tcx = self.tcx;
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
if tcx.is_closure(callsite.callee) {
let mut args = args.into_iter();
- let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
- let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
+ let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body_cache);
+ let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body_cache);
assert!(args.next().is_none());
let tuple = Place::from(tuple);
- let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind {
+ let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body_cache.body(), tcx).ty.kind {
s
} else {
bug!("Closure arguments are not passed as a tuple");
));
// Spill to a local to make e.g., `tmp0`.
- self.create_temp_if_necessary(tuple_field, callsite, caller_body)
+ self.create_temp_if_necessary(tuple_field, callsite, caller_body_cache)
});
closure_ref_arg.chain(tuple_tmp_args).collect()
} else {
args.into_iter()
- .map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
+ .map(|a| self.create_temp_if_necessary(a, callsite, caller_body_cache))
.collect()
}
}
&self,
arg: Operand<'tcx>,
callsite: &CallSite<'tcx>,
- caller_body: &mut Body<'tcx>,
+ caller_body_cache: &mut BodyCache<'tcx>,
) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
if let Operand::Move(place) = &arg {
if let Some(local) = place.as_local() {
- if caller_body.local_kind(local) == LocalKind::Temp {
+ if caller_body_cache.local_kind(local) == LocalKind::Temp {
// Reuse the operand if it's a temporary already
return local;
}
// Otherwise, create a temporary for the arg
let arg = Rvalue::Use(arg);
- let ty = arg.ty(caller_body, self.tcx);
+ let ty = arg.ty(caller_body_cache.body(), self.tcx);
let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
- let arg_tmp = caller_body.local_decls.push(arg_tmp);
+ let arg_tmp = caller_body_cache.local_decls.push(arg_tmp);
let stmt = Statement {
source_info: callsite.location,
kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
};
- caller_body[callsite.bb].statements.push(stmt);
+ caller_body_cache[callsite.bb].statements.push(stmt);
arg_tmp
}
}
use rustc::mir::{
Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyCache, Operand, ProjectionElem,
- Rvalue, Local
+ Rvalue, Local, read_only
};
use rustc::mir::visit::{MutVisitor, Visitor};
use rustc::ty::{self, TyCtxt};
// read-only so that we can do global analyses on the MIR in the process (e.g.
// `Place::ty()`).
let optimizations = {
+ let read_only_cache = read_only!(body_cache);
let mut optimization_finder = OptimizationFinder::new(body_cache, tcx);
- optimization_finder.visit_body(body_cache.read_only());
+ optimization_finder.visit_body(read_only_cache);
optimization_finder.optimizations
};
let (body, _) = tcx.mir_validated(def_id);
let mut body_cache = body.steal();
run_optimization_passes(tcx, &mut body_cache, def_id, None);
+ body_cache.ensure_predecessors();
tcx.arena.alloc(body_cache)
}
for (p, mut body_cache) in promoted.iter_enumerated_mut() {
run_optimization_passes(tcx, &mut body_cache, def_id, Some(p));
+ body_cache.ensure_predecessors();
}
tcx.intern_promoted(promoted)
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body_cache: &mut BodyCache<'tcx>) {
trace!("running SimplifyLocals on {:?}", source);
let locals = {
+ let read_only_cache = read_only!(body_cache);
let mut marker = DeclMarker {
locals: BitSet::new_empty(body_cache.local_decls.len()),
body: body_cache,
};
- marker.visit_body(body_cache.read_only());
+ marker.visit_body(read_only_cache);
// Return pointer and arguments are always live
marker.locals.insert(RETURN_PLACE);
for arg in body_cache.args_iter() {
let mut patch = MirPatch::new(body_cache);
let param_env = tcx.param_env(src.def_id());
{
+ let read_only_cache = read_only!(body_cache);
let mut visitor = UniformArrayMoveOutVisitor{ body: body_cache, patch: &mut patch, tcx, param_env};
- visitor.visit_body(body_cache.read_only());
+ visitor.visit_body(read_only_cache);
}
patch.apply(body_cache);
}
let mut patch = MirPatch::new(body_cache);
let param_env = tcx.param_env(src.def_id());
{
+ let read_only_cache = read_only!(body_cache);
let mut visitor = RestoreDataCollector {
locals_use: IndexVec::from_elem(LocalUse::new(), &body_cache.local_decls),
candidates: vec![],
};
- visitor.visit_body(body_cache.read_only());
+ visitor.visit_body(read_only_cache);
for candidate in &visitor.candidates {
let statement = &body_cache[candidate.block].statements[candidate.statement_index];