use polonius_engine::Atom;
use rustc_index::bit_set::BitMatrix;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{dominators, Dominators};
-use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::graph::{self, GraphSuccessors};
use rustc_index::vec::{Idx, IndexVec};
use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::sync::MappedReadGuard;
use rustc_macros::HashStable;
use rustc_serialize::{Encodable, Decodable};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::ops::{Index, IndexMut};
+use std::ops::Index;
use std::slice;
-use std::vec::IntoIter;
use std::{iter, mem, option, u32};
use syntax::ast::Name;
use syntax::symbol::Symbol;
use syntax_pos::{Span, DUMMY_SP};
pub use crate::mir::interpret::AssertMessage;
+pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
+pub use crate::read_only;
-mod cache;
+pub mod cache;
pub mod interpret;
pub mod mono;
pub mod tcx;
pub yield_ty: Option<Ty<'tcx>>,
/// Generator drop glue.
- pub generator_drop: Option<Box<Body<'tcx>>>,
+ pub generator_drop: Option<Box<BodyCache<'tcx>>>,
/// The layout of a generator. Produced by the state transformation.
pub generator_layout: Option<GeneratorLayout<'tcx>>,
/// A span representing this MIR, for error reporting.
pub span: Span,
-
- /// A cache for various calculations.
- cache: cache::Cache,
}
impl<'tcx> Body<'tcx> {
spread_arg: None,
var_debug_info,
span,
- cache: cache::Cache::new(),
control_flow_destroyed,
}
}
&self.basic_blocks
}
- #[inline]
- pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
- self.cache.invalidate();
- &mut self.basic_blocks
- }
-
- #[inline]
- pub fn basic_blocks_and_local_decls_mut(
- &mut self,
- ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
- self.cache.invalidate();
- (&mut self.basic_blocks, &mut self.local_decls)
- }
-
- #[inline]
- pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> {
- self.cache.predecessors(self)
- }
-
- #[inline]
- pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec<BasicBlock>> {
- MappedReadGuard::map(self.predecessors(), |p| &p[bb])
- }
-
- #[inline]
- pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
- let if_zero_locations = if loc.statement_index == 0 {
- let predecessor_blocks = self.predecessors_for(loc.block);
- let num_predecessor_blocks = predecessor_blocks.len();
- Some(
- (0..num_predecessor_blocks)
- .map(move |i| predecessor_blocks[i])
- .map(move |bb| self.terminator_loc(bb)),
- )
- } else {
- None
- };
-
- let if_not_zero_locations = if loc.statement_index == 0 {
- None
- } else {
- Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
- };
-
- if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
- }
-
- #[inline]
- pub fn dominators(&self) -> Dominators<BasicBlock> {
- dominators(self)
- }
-
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
/// `START_BLOCK`.
pub fn is_cfg_cyclic(&self) -> bool {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// invalidating statement indices in `Location`s.
pub fn make_statement_nop(&mut self, location: Location) {
- let block = &mut self[location.block];
+ let block = &mut self.basic_blocks[location.block];
debug_assert!(location.statement_index < block.statements.len());
block.statements[location.statement_index].make_nop()
}
}
}
-impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
- #[inline]
- fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
- &mut self.basic_blocks_mut()[index]
- }
-}
-
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable)]
pub enum ClearCrossCrate<T> {
Clear,
}
}
- AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| {
+ AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) {
let name = if tcx.sess.opts.debugging_opts.span_free_formats {
- format!("[closure@{:?}]", hir_id)
+ let substs = tcx.lift(&substs).unwrap();
+ format!(
+ "[closure@{}]",
+ tcx.def_path_str_with_substs(def_id, substs),
+ )
} else {
format!("[closure@{:?}]", tcx.hir().span(hir_id))
};
}
}
-impl<'tcx> graph::WithPredecessors for Body<'tcx> {
- fn predecessors(
- &self,
- node: Self::Node,
- ) -> <Self as GraphPredecessors<'_>>::Iter {
- self.predecessors_for(node).clone().into_iter()
- }
-}
-
impl<'tcx> graph::WithSuccessors for Body<'tcx> {
fn successors(
&self,
}
}
-impl<'a, 'b> graph::GraphPredecessors<'b> for Body<'a> {
- type Item = BasicBlock;
- type Iter = IntoIter<BasicBlock>;
-}
-
impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
type Item = BasicBlock;
type Iter = iter::Cloned<Successors<'b>>;
}
/// Returns `true` if `other` is earlier in the control flow graph than `self`.
- pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool {
+ pub fn is_predecessor_of<'tcx>(
+ &self,
+ other: Location,
+ body: ReadOnlyBodyCache<'_, 'tcx>
+ ) -> bool {
// If we are in the same block as the other location and are an earlier statement
// then we are a predecessor of `other`.
if self.block == other.block && self.statement_index < other.statement_index {
}
// If we're in another block, then we want to check that block is a predecessor of `other`.
- let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).clone();
+ let mut queue: Vec<BasicBlock> = body.predecessors_for(other.block).to_vec();
let mut visited = FxHashSet::default();
while let Some(block) = queue.pop() {
// If we haven't visited this block before, then make sure we visit it's predecessors.
if visited.insert(block) {
- queue.append(&mut body.predecessors_for(block).clone());
+ queue.extend(body.predecessors_for(block).iter().cloned());
} else {
continue;
}