Rollup merge of #98930 - tmiasko:pub-basic-blocks, r=oli-obk
Make MIR basic blocks field public This makes it possible to mutably borrow different fields of the MIR body without resorting to methods like `basic_blocks_local_decls_mut_and_var_debug_info`. To preserve validity of control flow graph caches in the presence of modifications, a new struct `BasicBlocks` wraps together basic blocks and control flow graph caches. The `BasicBlocks` dereferences to `IndexVec<BasicBlock, BasicBlockData>`. On the other hand a mutable access requires explicit `as_mut()` call.
This commit is contained in:
commit
71b3fbdb47
@ -1628,7 +1628,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location: Location,
|
||||
) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
|
||||
if location.statement_index == 0 {
|
||||
let predecessors = body.predecessors()[location.block].to_vec();
|
||||
let predecessors = body.basic_blocks.predecessors()[location.block].to_vec();
|
||||
Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
|
||||
} else {
|
||||
Either::Right(std::iter::once(Location {
|
||||
|
@ -26,7 +26,7 @@ pub(super) fn generate_invalidates<'tcx>(
|
||||
|
||||
if let Some(all_facts) = all_facts {
|
||||
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
||||
let dominators = body.dominators();
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
let mut ig = InvalidationGenerator {
|
||||
all_facts,
|
||||
borrow_set,
|
||||
|
@ -334,7 +334,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
};
|
||||
}
|
||||
|
||||
let dominators = body.dominators();
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
infcx,
|
||||
|
@ -258,7 +258,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
|
||||
let block = self.cx.elements.to_location(block_start).block;
|
||||
self.stack.extend(
|
||||
self.cx.body.predecessors()[block]
|
||||
self.cx.body.basic_blocks.predecessors()[block]
|
||||
.iter()
|
||||
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
|
||||
.map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
|
||||
@ -354,7 +354,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
}
|
||||
|
||||
let body = self.cx.body;
|
||||
for &pred_block in body.predecessors()[block].iter() {
|
||||
for &pred_block in body.basic_blocks.predecessors()[block].iter() {
|
||||
debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
|
||||
|
||||
// Check whether the variable is (at least partially)
|
||||
|
@ -15,7 +15,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
fx: &FunctionCx<'a, 'tcx, Bx>,
|
||||
) -> BitSet<mir::Local> {
|
||||
let mir = fx.mir;
|
||||
let dominators = mir.dominators();
|
||||
let dominators = mir.basic_blocks.dominators();
|
||||
let locals = mir
|
||||
.local_decls
|
||||
.iter()
|
||||
|
@ -856,7 +856,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
literal: ConstantKind::from_const(_const, tcx),
|
||||
}))
|
||||
};
|
||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||
let blocks = self.source.basic_blocks.as_mut();
|
||||
let local_decls = &mut self.source.local_decls;
|
||||
let loc = candidate.location;
|
||||
let statement = &mut blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
@ -865,7 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
|
||||
)) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = local_decls.local_decls()[place.local].ty;
|
||||
let ty = local_decls[place.local].ty;
|
||||
let span = statement.source_info.span;
|
||||
|
||||
let ref_ty = tcx.mk_ref(
|
||||
|
147
compiler/rustc_middle/src/mir/basic_blocks.rs
Normal file
147
compiler/rustc_middle/src/mir/basic_blocks.rs
Normal file
@ -0,0 +1,147 @@
|
||||
use crate::mir::graph_cyclic_cache::GraphIsCyclicCache;
|
||||
use crate::mir::predecessors::{PredecessorCache, Predecessors};
|
||||
use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources};
|
||||
use crate::mir::traversal::PostorderCache;
|
||||
use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK};
|
||||
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_data_structures::graph::dominators::{dominators, Dominators};
|
||||
use rustc_index::vec::IndexVec;
|
||||
|
||||
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct BasicBlocks<'tcx> {
|
||||
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
predecessor_cache: PredecessorCache,
|
||||
switch_source_cache: SwitchSourceCache,
|
||||
is_cyclic: GraphIsCyclicCache,
|
||||
postorder_cache: PostorderCache,
|
||||
}
|
||||
|
||||
impl<'tcx> BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
|
||||
BasicBlocks {
|
||||
basic_blocks,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
switch_source_cache: SwitchSourceCache::new(),
|
||||
is_cyclic: GraphIsCyclicCache::new(),
|
||||
postorder_cache: PostorderCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
|
||||
#[inline]
|
||||
pub fn is_cfg_cyclic(&self) -> bool {
|
||||
self.is_cyclic.is_cyclic(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dominators(&self) -> Dominators<BasicBlock> {
|
||||
dominators(&self)
|
||||
}
|
||||
|
||||
/// Returns predecessors for each basic block.
|
||||
#[inline]
|
||||
pub fn predecessors(&self) -> &Predecessors {
|
||||
self.predecessor_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
/// Returns basic blocks in a postorder.
|
||||
#[inline]
|
||||
pub fn postorder(&self) -> &[BasicBlock] {
|
||||
self.postorder_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
/// `switch_sources()[&(target, switch)]` returns a list of switch
|
||||
/// values that lead to a `target` block from a `switch` block.
|
||||
#[inline]
|
||||
pub fn switch_sources(&self) -> &SwitchSources {
|
||||
self.switch_source_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
/// Returns mutable reference to basic blocks. Invalidates CFG cache.
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
self.invalidate_cfg_cache();
|
||||
&mut self.basic_blocks
|
||||
}
|
||||
|
||||
/// Get mutable access to basic blocks without invalidating the CFG cache.
|
||||
///
|
||||
/// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change
|
||||
/// the CFG. This means that
|
||||
///
|
||||
/// 1) The number of basic blocks remains unchanged
|
||||
/// 2) The set of successors of each terminator remains unchanged.
|
||||
/// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
|
||||
/// kind is not changed.
|
||||
///
|
||||
/// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`].
|
||||
#[inline]
|
||||
pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
&mut self.basic_blocks
|
||||
}
|
||||
|
||||
/// Invalidates cached information about the CFG.
|
||||
///
|
||||
/// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`].
|
||||
/// All other methods that allow you to mutate the basic blocks also call this method
|
||||
/// themselves, thereby avoiding any risk of accidentaly cache invalidation.
|
||||
pub fn invalidate_cfg_cache(&mut self) {
|
||||
self.predecessor_cache.invalidate();
|
||||
self.switch_source_cache.invalidate();
|
||||
self.is_cyclic.invalidate();
|
||||
self.postorder_cache.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
|
||||
type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
&self.basic_blocks
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
|
||||
type Node = BasicBlock;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.basic_blocks.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn start_node(&self) -> Self::Node {
|
||||
START_BLOCK
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
|
||||
self.basic_blocks[node].terminator().successors()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = Successors<'b>;
|
||||
}
|
||||
|
||||
impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
|
||||
self.predecessors()[node].iter().copied()
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
use crate::mir::interpret::{
|
||||
AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar,
|
||||
};
|
||||
use crate::mir::traversal::PostorderCache;
|
||||
use crate::mir::visit::MirVisitable;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
|
||||
@ -27,8 +26,7 @@ use rustc_target::abi::{Size, VariantIdx};
|
||||
use polonius_engine::Atom;
|
||||
pub use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::dominators::{dominators, Dominators};
|
||||
use rustc_data_structures::graph::{self, GraphSuccessors};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_index::bit_set::BitMatrix;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
@ -43,11 +41,10 @@ use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||
use std::ops::{ControlFlow, Index, IndexMut};
|
||||
use std::{iter, mem};
|
||||
|
||||
use self::graph_cyclic_cache::GraphIsCyclicCache;
|
||||
use self::predecessors::{PredecessorCache, Predecessors};
|
||||
pub use self::query::*;
|
||||
use self::switch_sources::{SwitchSourceCache, SwitchSources};
|
||||
pub use basic_blocks::BasicBlocks;
|
||||
|
||||
mod basic_blocks;
|
||||
pub mod coverage;
|
||||
mod generic_graph;
|
||||
pub mod generic_graphviz;
|
||||
@ -189,7 +186,7 @@ pub struct GeneratorInfo<'tcx> {
|
||||
pub struct Body<'tcx> {
|
||||
/// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`]
|
||||
/// that indexes into this vector.
|
||||
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
pub basic_blocks: BasicBlocks<'tcx>,
|
||||
|
||||
/// Records how far through the "desugaring and optimization" process this particular
|
||||
/// MIR has traversed. This is particularly useful when inlining, since in that context
|
||||
@ -257,11 +254,6 @@ pub struct Body<'tcx> {
|
||||
/// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
|
||||
pub is_polymorphic: bool,
|
||||
|
||||
predecessor_cache: PredecessorCache,
|
||||
switch_source_cache: SwitchSourceCache,
|
||||
is_cyclic: GraphIsCyclicCache,
|
||||
postorder_cache: PostorderCache,
|
||||
|
||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
@ -289,7 +281,7 @@ impl<'tcx> Body<'tcx> {
|
||||
let mut body = Body {
|
||||
phase: MirPhase::Built,
|
||||
source,
|
||||
basic_blocks,
|
||||
basic_blocks: BasicBlocks::new(basic_blocks),
|
||||
source_scopes,
|
||||
generator: generator_kind.map(|generator_kind| {
|
||||
Box::new(GeneratorInfo {
|
||||
@ -307,10 +299,6 @@ impl<'tcx> Body<'tcx> {
|
||||
span,
|
||||
required_consts: Vec::new(),
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
switch_source_cache: SwitchSourceCache::new(),
|
||||
is_cyclic: GraphIsCyclicCache::new(),
|
||||
postorder_cache: PostorderCache::new(),
|
||||
tainted_by_errors,
|
||||
};
|
||||
body.is_polymorphic = body.has_param_types_or_consts();
|
||||
@ -326,7 +314,7 @@ impl<'tcx> Body<'tcx> {
|
||||
let mut body = Body {
|
||||
phase: MirPhase::Built,
|
||||
source: MirSource::item(CRATE_DEF_ID.to_def_id()),
|
||||
basic_blocks,
|
||||
basic_blocks: BasicBlocks::new(basic_blocks),
|
||||
source_scopes: IndexVec::new(),
|
||||
generator: None,
|
||||
local_decls: IndexVec::new(),
|
||||
@ -337,10 +325,6 @@ impl<'tcx> Body<'tcx> {
|
||||
required_consts: Vec::new(),
|
||||
var_debug_info: Vec::new(),
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
switch_source_cache: SwitchSourceCache::new(),
|
||||
is_cyclic: GraphIsCyclicCache::new(),
|
||||
postorder_cache: PostorderCache::new(),
|
||||
tainted_by_errors: None,
|
||||
};
|
||||
body.is_polymorphic = body.has_param_types_or_consts();
|
||||
@ -354,74 +338,7 @@ impl<'tcx> Body<'tcx> {
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
// Because the user could mutate basic block terminators via this reference, we need to
|
||||
// invalidate the caches.
|
||||
//
|
||||
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
|
||||
// invalidate the caches.
|
||||
self.invalidate_cfg_cache();
|
||||
&mut self.basic_blocks
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks_and_local_decls_mut(
|
||||
&mut self,
|
||||
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
|
||||
self.invalidate_cfg_cache();
|
||||
(&mut self.basic_blocks, &mut self.local_decls)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks_local_decls_mut_and_var_debug_info(
|
||||
&mut self,
|
||||
) -> (
|
||||
&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
&mut LocalDecls<'tcx>,
|
||||
&mut Vec<VarDebugInfo<'tcx>>,
|
||||
) {
|
||||
self.invalidate_cfg_cache();
|
||||
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
||||
}
|
||||
|
||||
/// Get mutable access to parts of the Body without invalidating the CFG cache.
|
||||
///
|
||||
/// By calling this method instead of eg [`Body::basic_blocks_mut`], you promise not to change
|
||||
/// the CFG. This means that
|
||||
///
|
||||
/// 1) The number of basic blocks remains unchanged
|
||||
/// 2) The set of successors of each terminator remains unchanged.
|
||||
/// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
|
||||
/// kind is not changed.
|
||||
///
|
||||
/// If any of these conditions cannot be upheld, you should call [`Body::invalidate_cfg_cache`].
|
||||
#[inline]
|
||||
pub fn basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate(
|
||||
&mut self,
|
||||
) -> (
|
||||
&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
&mut LocalDecls<'tcx>,
|
||||
&mut Vec<VarDebugInfo<'tcx>>,
|
||||
) {
|
||||
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
||||
}
|
||||
|
||||
/// Invalidates cached information about the CFG.
|
||||
///
|
||||
/// You will only ever need this if you have also called
|
||||
/// [`Body::basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate`]. All other methods
|
||||
/// that allow you to mutate the body also call this method themselves, thereby avoiding any
|
||||
/// risk of accidentaly cache invalidation.
|
||||
pub fn invalidate_cfg_cache(&mut self) {
|
||||
self.predecessor_cache.invalidate();
|
||||
self.switch_source_cache.invalidate();
|
||||
self.is_cyclic.invalidate();
|
||||
self.postorder_cache.invalidate();
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.is_cyclic.is_cyclic(self)
|
||||
self.basic_blocks.as_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -495,14 +412,6 @@ impl<'tcx> Body<'tcx> {
|
||||
self.local_decls.drain(self.arg_count + 1..)
|
||||
}
|
||||
|
||||
/// 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.basic_blocks[location.block];
|
||||
debug_assert!(location.statement_index < block.statements.len());
|
||||
block.statements[location.statement_index].make_nop()
|
||||
}
|
||||
|
||||
/// Returns the source info associated with `location`.
|
||||
pub fn source_info(&self, location: Location) -> &SourceInfo {
|
||||
let block = &self[location.block];
|
||||
@ -538,23 +447,6 @@ impl<'tcx> Body<'tcx> {
|
||||
.unwrap_or_else(|| Either::Right(block_data.terminator()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn predecessors(&self) -> &Predecessors {
|
||||
self.predecessor_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
/// `body.switch_sources()[&(target, switch)]` returns a list of switch
|
||||
/// values that lead to a `target` block from a `switch` block.
|
||||
#[inline]
|
||||
pub fn switch_sources(&self) -> &SwitchSources {
|
||||
self.switch_source_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dominators(&self) -> Dominators<BasicBlock> {
|
||||
dominators(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn yield_ty(&self) -> Option<Ty<'tcx>> {
|
||||
self.generator.as_ref().and_then(|generator| generator.yield_ty)
|
||||
@ -599,7 +491,7 @@ impl<'tcx> Index<BasicBlock> for Body<'tcx> {
|
||||
impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
|
||||
&mut self.basic_blocks_mut()[index]
|
||||
&mut self.basic_blocks.as_mut()[index]
|
||||
}
|
||||
}
|
||||
|
||||
@ -2890,48 +2782,6 @@ fn pretty_print_const_value<'tcx>(
|
||||
})
|
||||
}
|
||||
|
||||
impl<'tcx> graph::DirectedGraph for Body<'tcx> {
|
||||
type Node = BasicBlock;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithNumNodes for Body<'tcx> {
|
||||
#[inline]
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.basic_blocks.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithStartNode for Body<'tcx> {
|
||||
#[inline]
|
||||
fn start_node(&self) -> Self::Node {
|
||||
START_BLOCK
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithSuccessors for Body<'tcx> {
|
||||
#[inline]
|
||||
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
self.basic_blocks[node].terminator().successors()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = Successors<'b>;
|
||||
}
|
||||
|
||||
impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithPredecessors for Body<'tcx> {
|
||||
#[inline]
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
|
||||
self.predecessors()[node].iter().copied()
|
||||
}
|
||||
}
|
||||
|
||||
/// `Location` represents the position of the start of the statement; or, if
|
||||
/// `statement_index` equals the number of statements, then the start of the
|
||||
/// terminator.
|
||||
@ -2968,7 +2818,7 @@ impl Location {
|
||||
return true;
|
||||
}
|
||||
|
||||
let predecessors = body.predecessors();
|
||||
let predecessors = body.basic_blocks.predecessors();
|
||||
|
||||
// If we're in another block, then we want to check that block is a predecessor of `other`.
|
||||
let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec();
|
||||
|
@ -104,22 +104,25 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
|
||||
///
|
||||
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
|
||||
pub struct Postorder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
visited: BitSet<BasicBlock>,
|
||||
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
|
||||
root_is_start_block: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
||||
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
|
||||
pub fn new(
|
||||
basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
root: BasicBlock,
|
||||
) -> Postorder<'a, 'tcx> {
|
||||
let mut po = Postorder {
|
||||
body,
|
||||
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||
basic_blocks,
|
||||
visited: BitSet::new_empty(basic_blocks.len()),
|
||||
visit_stack: Vec::new(),
|
||||
root_is_start_block: root == START_BLOCK,
|
||||
};
|
||||
|
||||
let data = &po.body[root];
|
||||
let data = &po.basic_blocks[root];
|
||||
|
||||
if let Some(ref term) = data.terminator {
|
||||
po.visited.insert(root);
|
||||
@ -190,7 +193,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
||||
};
|
||||
|
||||
if self.visited.insert(bb) {
|
||||
if let Some(term) = &self.body[bb].terminator {
|
||||
if let Some(term) = &self.basic_blocks[bb].terminator {
|
||||
self.visit_stack.push((bb, term.successors()));
|
||||
}
|
||||
}
|
||||
@ -199,7 +202,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
|
||||
Postorder::new(body, START_BLOCK)
|
||||
Postorder::new(&body.basic_blocks, START_BLOCK)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
|
||||
@ -211,12 +214,12 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
|
||||
self.traverse_successor();
|
||||
}
|
||||
|
||||
next.map(|(bb, _)| (bb, &self.body[bb]))
|
||||
next.map(|(bb, _)| (bb, &self.basic_blocks[bb]))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// All the blocks, minus the number of blocks we've visited.
|
||||
let upper = self.body.basic_blocks().len() - self.visited.count();
|
||||
let upper = self.basic_blocks.len() - self.visited.count();
|
||||
|
||||
let lower = if self.root_is_start_block {
|
||||
// We will visit all remaining blocks exactly once.
|
||||
@ -263,10 +266,8 @@ pub struct ReversePostorder<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
|
||||
pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
|
||||
let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect();
|
||||
|
||||
let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect();
|
||||
let len = blocks.len();
|
||||
|
||||
ReversePostorder { body, blocks, idx: len }
|
||||
}
|
||||
}
|
||||
@ -334,10 +335,8 @@ impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> {
|
||||
impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {}
|
||||
|
||||
pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
|
||||
let blocks = body.postorder_cache.compute(body);
|
||||
|
||||
let blocks = body.basic_blocks.postorder();
|
||||
let len = blocks.len();
|
||||
|
||||
ReversePostorderIter { body, blocks, idx: len }
|
||||
}
|
||||
|
||||
@ -360,7 +359,7 @@ impl PostorderCache {
|
||||
|
||||
/// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
|
||||
#[inline]
|
||||
pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] {
|
||||
pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] {
|
||||
self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use rustc_data_structures::graph::iterate::{
|
||||
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||
};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
|
||||
use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
|
||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
|
||||
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
|
||||
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
||||
@ -30,7 +30,9 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
};
|
||||
|
||||
let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_substs };
|
||||
if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
|
||||
if let Some(NonRecursive) =
|
||||
TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if vis.reachable_recursive_calls.is_empty() {
|
||||
@ -101,7 +103,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
|
||||
impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||
type BreakVal = NonRecursive;
|
||||
|
||||
fn node_examined(
|
||||
|
@ -228,7 +228,7 @@ impl Direction for Backward {
|
||||
) where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
for pred in body.predecessors()[bb].iter().copied() {
|
||||
for pred in body.basic_blocks.predecessors()[bb].iter().copied() {
|
||||
match body[pred].terminator().kind {
|
||||
// Apply terminator-specific edge effects.
|
||||
//
|
||||
@ -316,7 +316,7 @@ where
|
||||
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
|
||||
assert!(!self.effects_applied);
|
||||
|
||||
let values = &self.body.switch_sources()[&(self.bb, self.pred)];
|
||||
let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
|
||||
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
|
||||
|
||||
let mut tmp = None;
|
||||
|
@ -101,7 +101,7 @@ where
|
||||
// transfer function for each block exactly once (assuming that we process blocks in RPO).
|
||||
//
|
||||
// In this case, there's no need to compute the block transfer functions ahead of time.
|
||||
if !body.is_cfg_cyclic() {
|
||||
if !body.basic_blocks.is_cfg_cyclic() {
|
||||
return Self::new(tcx, body, analysis, None);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards {
|
||||
impl AddCallGuards {
|
||||
pub fn add_call_guards(&self, body: &mut Body<'_>) {
|
||||
let mut pred_count: IndexVec<_, _> =
|
||||
body.predecessors().iter().map(|ps| ps.len()).collect();
|
||||
body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect();
|
||||
pred_count[START_BLOCK] += 1;
|
||||
|
||||
// We need a place to store the new blocks generated
|
||||
|
@ -91,7 +91,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||
super::add_call_guards::AllCallEdges.run_pass(tcx, body);
|
||||
|
||||
let (span, arg_count) = (body.span, body.arg_count);
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
let basic_blocks = body.basic_blocks.as_mut();
|
||||
let local_decls = &body.local_decls;
|
||||
let needs_retag = |place: &Place<'tcx>| {
|
||||
// FIXME: Instead of giving up for unstable places, we should introduce
|
||||
// a temporary and retag on that.
|
||||
|
@ -80,7 +80,7 @@ impl CoverageGraph {
|
||||
IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
|
||||
IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
|
||||
) {
|
||||
let num_basic_blocks = mir_body.num_nodes();
|
||||
let num_basic_blocks = mir_body.basic_blocks.len();
|
||||
let mut bcbs = IndexVec::with_capacity(num_basic_blocks);
|
||||
let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks);
|
||||
|
||||
@ -95,7 +95,7 @@ impl CoverageGraph {
|
||||
let mut basic_blocks = Vec::new();
|
||||
for (bb, data) in mir_cfg_without_unwind {
|
||||
if let Some(last) = basic_blocks.last() {
|
||||
let predecessors = &mir_body.predecessors()[bb];
|
||||
let predecessors = &mir_body.basic_blocks.predecessors()[bb];
|
||||
if predecessors.len() > 1 || !predecessors.contains(last) {
|
||||
// The `bb` has more than one _incoming_ edge, and should start its own
|
||||
// `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet
|
||||
|
@ -321,7 +321,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
|
||||
let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
|
||||
let mut initial_spans =
|
||||
Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2);
|
||||
for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
|
||||
initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data));
|
||||
}
|
||||
|
@ -222,6 +222,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
|
||||
bb,
|
||||
debug::term_type(&data.terminator().kind),
|
||||
mir_body
|
||||
.basic_blocks
|
||||
.successors(bb)
|
||||
.map(|successor| { format!(" {:?} -> {:?};", bb, successor) })
|
||||
.join("\n")
|
||||
|
@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
||||
return;
|
||||
}
|
||||
|
||||
let bbs = body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0;
|
||||
let bbs = body.basic_blocks.as_mut_preserves_cfg();
|
||||
for Location { block, statement_index } in patch {
|
||||
bbs[block].statements[statement_index].make_nop();
|
||||
}
|
||||
|
@ -11,9 +11,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let (basic_blocks, local_decls, _) =
|
||||
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||
let local_decls = &*local_decls;
|
||||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||
for bb in basic_blocks {
|
||||
bb.expand_statements(|stmt| {
|
||||
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
|
||||
@ -38,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
||||
Some(expand_aggregate(
|
||||
lhs,
|
||||
operands.into_iter().map(|op| {
|
||||
let ty = op.ty(local_decls, tcx);
|
||||
let ty = op.ty(&body.local_decls, tcx);
|
||||
(op, ty)
|
||||
}),
|
||||
*kind,
|
||||
|
@ -110,13 +110,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
|
||||
|
||||
let patch = MirPatch::new(body);
|
||||
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
let local_decls = &mut body.local_decls;
|
||||
|
||||
let mut visitor =
|
||||
ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
|
||||
|
||||
for (block, BasicBlockData { statements, terminator, .. }) in
|
||||
basic_blocks.iter_enumerated_mut()
|
||||
body.basic_blocks.as_mut().iter_enumerated_mut()
|
||||
{
|
||||
let mut index = 0;
|
||||
for statement in statements {
|
||||
|
@ -16,9 +16,8 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
let ctx = InstCombineContext { tcx, local_decls };
|
||||
for block in basic_blocks.iter_mut() {
|
||||
let ctx = InstCombineContext { tcx, local_decls: &body.local_decls };
|
||||
for block in body.basic_blocks.as_mut() {
|
||||
for statement in block.statements.iter_mut() {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box (_place, ref mut rvalue)) => {
|
||||
|
@ -11,8 +11,8 @@ pub struct LowerIntrinsics;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
for block in basic_blocks {
|
||||
let local_decls = &body.local_decls;
|
||||
for block in body.basic_blocks.as_mut() {
|
||||
let terminator = block.terminator.as_mut().unwrap();
|
||||
if let TerminatorKind::Call { func, args, destination, target, .. } =
|
||||
&mut terminator.kind
|
||||
|
@ -27,12 +27,10 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
};
|
||||
|
||||
// The one successor remains unchanged, so no need to invalidate
|
||||
let (basic_blocks, local_decls, _) =
|
||||
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||
|
||||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||
for block in basic_blocks {
|
||||
// lower `<[_]>::len` calls
|
||||
lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id);
|
||||
lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
||||
let def_id = body.source.def_id();
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
let bbs = body.basic_blocks.as_mut();
|
||||
let mut should_cleanup = false;
|
||||
'outer: for bb_idx in bbs.indices() {
|
||||
if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) {
|
||||
@ -108,7 +108,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
||||
|
||||
// Introduce a temporary for the discriminant value.
|
||||
let source_info = bbs[bb_idx].terminator().source_info;
|
||||
let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span));
|
||||
let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span));
|
||||
|
||||
// We already checked that first and second are different blocks,
|
||||
// and bb_idx has a different terminator from both of them.
|
||||
|
@ -33,8 +33,8 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
|
||||
|
||||
pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// We don't ever touch terminators, so no need to invalidate the CFG cache
|
||||
let (basic_blocks, local_decls, _) =
|
||||
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||
let local_decls = &mut body.local_decls;
|
||||
|
||||
// do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
|
||||
let mut interesting_locals = BitSet::new_empty(local_decls.len());
|
||||
|
@ -133,7 +133,7 @@ fn find_local_assigned_to_return_place(
|
||||
return local;
|
||||
}
|
||||
|
||||
match body.predecessors()[block].as_slice() {
|
||||
match body.basic_blocks.predecessors()[block].as_slice() {
|
||||
&[pred] => block = pred,
|
||||
_ => return None,
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
|
||||
}
|
||||
|
||||
trace!("Running RemoveStorageMarkers on {:?}", body.source);
|
||||
for data in body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate().0 {
|
||||
for data in body.basic_blocks.as_mut_preserves_cfg() {
|
||||
data.statements.retain(|statement| match statement.kind {
|
||||
StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
|
@ -20,11 +20,10 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
|
||||
let param_env = tcx.param_env_reveal_all_normalized(did);
|
||||
let mut should_simplify = false;
|
||||
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
for block in basic_blocks {
|
||||
for block in body.basic_blocks.as_mut() {
|
||||
let terminator = block.terminator_mut();
|
||||
if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
|
||||
let ty = place.ty(local_decls, tcx);
|
||||
let ty = place.ty(&body.local_decls, tcx);
|
||||
if ty.ty.needs_drop(tcx, param_env) {
|
||||
continue;
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
|
||||
return;
|
||||
}
|
||||
let param_env = tcx.param_env(body.source.def_id());
|
||||
let (basic_blocks, local_decls, _) =
|
||||
body.basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate();
|
||||
for block in basic_blocks.iter_mut() {
|
||||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||
let local_decls = &body.local_decls;
|
||||
for block in basic_blocks {
|
||||
for statement in block.statements.iter_mut() {
|
||||
if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
|
||||
statement.kind
|
||||
|
@ -61,7 +61,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
|
||||
/// Returns the amount of blocks that were duplicated
|
||||
pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||
let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
|
||||
let predecessors = body.predecessors();
|
||||
let predecessors = body.basic_blocks.predecessors();
|
||||
'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
|
||||
if let TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
|
||||
|
@ -386,14 +386,17 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
|
||||
trace!("running SimplifyArmIdentity on {:?}", source);
|
||||
|
||||
let local_uses = LocalUseCounter::get_local_uses(body);
|
||||
let (basic_blocks, local_decls, debug_info) =
|
||||
body.basic_blocks_local_decls_mut_and_var_debug_info();
|
||||
for bb in basic_blocks {
|
||||
for bb in body.basic_blocks.as_mut() {
|
||||
if let Some(opt_info) =
|
||||
get_arm_identity_info(&bb.statements, local_decls.len(), debug_info)
|
||||
get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info)
|
||||
{
|
||||
trace!("got opt_info = {:#?}", opt_info);
|
||||
if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) {
|
||||
if !optimization_applies(
|
||||
&opt_info,
|
||||
&body.local_decls,
|
||||
&local_uses,
|
||||
&body.var_debug_info,
|
||||
) {
|
||||
debug!("optimization skipped for {:?}", source);
|
||||
continue;
|
||||
}
|
||||
@ -431,7 +434,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
|
||||
|
||||
// Fix the debug info to point to the right local
|
||||
for dbg_index in opt_info.dbg_info_to_adjust {
|
||||
let dbg_info = &mut debug_info[dbg_index];
|
||||
let dbg_info = &mut body.var_debug_info[dbg_index];
|
||||
assert!(
|
||||
matches!(dbg_info.value, VarDebugInfoContents::Place(_)),
|
||||
"value was not a Place"
|
||||
|
@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
|
||||
// `arg` is a reference as it is `.deref()`ed in the previous block.
|
||||
// Look into the predecessor block and find out the source of deref.
|
||||
|
||||
let ps = &mir.predecessors()[bb];
|
||||
let ps = &mir.basic_blocks.predecessors()[bb];
|
||||
if ps.len() != 1 {
|
||||
continue;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user