summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_dataflow
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_mir_dataflow
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_dataflow')
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs117
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs112
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs70
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs114
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs98
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs61
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs17
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs45
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs18
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs28
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs87
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs154
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs74
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs25
-rw-r--r--compiler/rustc_mir_dataflow/src/un_derefer.rs22
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs8
18 files changed, 601 insertions, 464 deletions
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index d615c83d6..0540a5e94 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -409,14 +409,21 @@ where
self.drop_ladder(fields, succ, unwind).0
}
+ /// Drops the T contained in a `Box<T>` if it has not been moved out of
#[instrument(level = "debug", ret)]
- fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
+ fn open_drop_for_box_contents(
+ &mut self,
+ adt: ty::AdtDef<'tcx>,
+ substs: SubstsRef<'tcx>,
+ succ: BasicBlock,
+ unwind: Unwind,
+ ) -> BasicBlock {
// drop glue is sent straight to codegen
// box cannot be directly dereferenced
let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs);
let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant();
let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), substs);
- let ptr_ty = self.tcx().mk_imm_ptr(substs[0].expect_ty());
+ let ptr_ty = Ty::new_imm_ptr(self.tcx(), substs[0].expect_ty());
let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty);
let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty);
@@ -425,11 +432,7 @@ where
let interior_path = self.elaborator.deref_subpath(self.path);
- let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
- let unwind_succ =
- self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
-
- self.drop_subpath(interior, interior_path, succ, unwind_succ)
+ self.drop_subpath(interior, interior_path, succ, unwind)
}
#[instrument(level = "debug", ret)]
@@ -453,7 +456,15 @@ where
self.open_drop_for_adt_contents(adt, substs)
};
- if adt.has_dtor(self.tcx()) {
+ if adt.is_box() {
+ // we need to drop the inside of the box before running the destructor
+ let succ = self.destructor_call_block(contents_drop);
+ let unwind = contents_drop
+ .1
+ .map(|unwind| self.destructor_call_block((unwind, Unwind::InCleanup)));
+
+ self.open_drop_for_box_contents(adt, substs, succ, unwind)
+ } else if adt.has_dtor(self.tcx()) {
self.destructor_call_block(contents_drop)
} else {
contents_drop.0
@@ -617,17 +628,20 @@ where
let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let ty = self.place_ty(self.place);
- let ref_ty =
- tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut });
+ let ref_ty = Ty::new_ref(
+ tcx,
+ tcx.lifetimes.re_erased,
+ ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut },
+ );
let ref_place = self.new_temp(ref_ty);
- let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
+ let unit_temp = Place::from(self.new_temp(Ty::new_unit(tcx)));
let result = BasicBlockData {
statements: vec![self.assign(
Place::from(ref_place),
Rvalue::Ref(
tcx.lifetimes.re_erased,
- BorrowKind::Mut { allow_two_phase_borrow: false },
+ BorrowKind::Mut { kind: MutBorrowKind::Default },
self.place,
),
)],
@@ -643,14 +657,20 @@ where
destination: unit_temp,
target: Some(succ),
unwind: unwind.into_action(),
- from_hir_call: true,
+ call_source: CallSource::Misc,
fn_span: self.source_info.span,
},
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
- self.elaborator.patch().new_block(result)
+
+ let destructor_block = self.elaborator.patch().new_block(result);
+
+ let block_start = Location { block: destructor_block, statement_index: 0 };
+ self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
+
+ self.drop_flag_test_block(destructor_block, succ, unwind)
}
/// Create a loop that drops an array:
@@ -676,7 +696,7 @@ where
let move_ = |place: Place<'tcx>| Operand::Move(place);
let tcx = self.tcx();
- let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
+ let ptr_ty = Ty::new_ptr(tcx, ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
let ptr = Place::from(self.new_temp(ptr_ty));
let can_go = Place::from(self.new_temp(tcx.types.bool));
let one = self.constant_usize(1);
@@ -851,13 +871,7 @@ where
self.open_drop_for_tuple(&tys)
}
ty::Tuple(fields) => self.open_drop_for_tuple(fields),
- ty::Adt(def, substs) => {
- if def.is_box() {
- self.open_drop_for_box(*def, substs)
- } else {
- self.open_drop_for_adt(*def, substs)
- }
- }
+ ty::Adt(def, substs) => self.open_drop_for_adt(*def, substs),
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
ty::Array(ety, size) => {
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
@@ -905,65 +919,6 @@ where
blk
}
- /// Creates a block that frees the backing memory of a `Box` if its drop is required (either
- /// statically or by checking its drop flag).
- ///
- /// The contained value will not be dropped.
- fn box_free_block(
- &mut self,
- adt: ty::AdtDef<'tcx>,
- substs: SubstsRef<'tcx>,
- target: BasicBlock,
- unwind: Unwind,
- ) -> BasicBlock {
- let block = self.unelaborated_free_block(adt, substs, target, unwind);
- self.drop_flag_test_block(block, target, unwind)
- }
-
- /// Creates a block that frees the backing memory of a `Box` (without dropping the contained
- /// value).
- fn unelaborated_free_block(
- &mut self,
- adt: ty::AdtDef<'tcx>,
- substs: SubstsRef<'tcx>,
- target: BasicBlock,
- unwind: Unwind,
- ) -> BasicBlock {
- let tcx = self.tcx();
- let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
- let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span));
- let args = adt
- .variant(FIRST_VARIANT)
- .fields
- .iter()
- .enumerate()
- .map(|(i, f)| {
- let field = FieldIdx::new(i);
- let field_ty = f.ty(tcx, substs);
- Operand::Move(tcx.mk_place_field(self.place, field, field_ty))
- })
- .collect();
-
- let call = TerminatorKind::Call {
- func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
- args,
- destination: unit_temp,
- target: Some(target),
- unwind: if unwind.is_cleanup() {
- UnwindAction::Terminate
- } else {
- UnwindAction::Continue
- },
- from_hir_call: false,
- fn_span: self.source_info.span,
- }; // FIXME(#43234)
- let free_block = self.new_block(unwind, call);
-
- let block_start = Location { block: free_block, statement_index: 0 };
- self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
- free_block
- }
-
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let block = TerminatorKind::Drop {
place: self.place,
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index f3b5544aa..c978bddfe 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,18 +1,60 @@
//! Random access inspection of the results of a dataflow analysis.
-use crate::framework::BitSetExt;
+use crate::{framework::BitSetExt, CloneAnalysis};
-use std::borrow::Borrow;
+use std::borrow::{Borrow, BorrowMut};
use std::cmp::Ordering;
#[cfg(debug_assertions)]
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Location};
-use super::{Analysis, Direction, Effect, EffectIndex, Results};
+use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results, ResultsCloned};
+
+// `AnalysisResults` is needed as an impl such as the following has an unconstrained type
+// parameter:
+// ```
+// impl<'tcx, A, E, R> ResultsCursor<'_, 'tcx, A, R>
+// where
+// A: Analysis<'tcx>,
+// E: Borrow<EntrySets<'tcx, A>>,
+// R: Results<'tcx, A, E>,
+// {}
+// ```
+
+/// A type representing the analysis results consumed by a `ResultsCursor`.
+pub trait AnalysisResults<'tcx, A>: BorrowMut<Results<'tcx, A, Self::EntrySets>>
+where
+ A: Analysis<'tcx>,
+{
+ /// The type containing the entry sets for this `Results` type.
+ ///
+ /// Should be either `EntrySets<'tcx, A>` or `&EntrySets<'tcx, A>`.
+ type EntrySets: Borrow<EntrySets<'tcx, A>>;
+}
+impl<'tcx, A, E> AnalysisResults<'tcx, A> for Results<'tcx, A, E>
+where
+ A: Analysis<'tcx>,
+ E: Borrow<EntrySets<'tcx, A>>,
+{
+ type EntrySets = E;
+}
+impl<'a, 'tcx, A, E> AnalysisResults<'tcx, A> for &'a mut Results<'tcx, A, E>
+where
+ A: Analysis<'tcx>,
+ E: Borrow<EntrySets<'tcx, A>>,
+{
+ type EntrySets = E;
+}
/// A `ResultsCursor` that borrows the underlying `Results`.
-pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
+pub type ResultsRefCursor<'res, 'mir, 'tcx, A> =
+ ResultsCursor<'mir, 'tcx, A, &'res mut Results<'tcx, A>>;
+
+/// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This
+/// allows multiple cursors over the same `Results`.
+pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> =
+ ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>;
/// Allows random access inspection of the results of a dataflow analysis.
///
@@ -45,7 +87,38 @@ where
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
A: Analysis<'tcx>,
- R: Borrow<Results<'tcx, A>>,
+{
+ /// Returns the dataflow state at the current location.
+ pub fn get(&self) -> &A::Domain {
+ &self.state
+ }
+
+ /// Returns the body this analysis was run on.
+ pub fn body(&self) -> &'mir mir::Body<'tcx> {
+ self.body
+ }
+
+ /// Unwraps this cursor, returning the underlying `Results`.
+ pub fn into_results(self) -> R {
+ self.results
+ }
+}
+
+impl<'res, 'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>
+where
+ A: Analysis<'tcx> + CloneAnalysis,
+{
+ /// Creates a new cursor over the same `Results`. Note that the cursor's position is *not*
+ /// copied.
+ pub fn new_cursor(&self) -> Self {
+ Self::new(self.body, self.results.reclone_analysis())
+ }
+}
+
+impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
+where
+ A: Analysis<'tcx>,
+ R: AnalysisResults<'tcx, A>,
{
/// Returns a new cursor that can inspect `results`.
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
@@ -74,8 +147,13 @@ where
}
/// Returns the underlying `Results`.
- pub fn results(&self) -> &Results<'tcx, A> {
- &self.results.borrow()
+ pub fn results(&mut self) -> &Results<'tcx, A, R::EntrySets> {
+ self.results.borrow()
+ }
+
+ /// Returns the underlying `Results`.
+ pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> {
+ self.results.borrow_mut()
}
/// Returns the `Analysis` used to generate the underlying `Results`.
@@ -83,9 +161,14 @@ where
&self.results.borrow().analysis
}
- /// Returns the dataflow state at the current location.
- pub fn get(&self) -> &A::Domain {
- &self.state
+ /// Returns the `Analysis` used to generate the underlying `Results`.
+ pub fn mut_analysis(&mut self) -> &mut A {
+ &mut self.results.borrow_mut().analysis
+ }
+
+ /// Returns both the dataflow state at the current location and the `Analysis`.
+ pub fn get_with_analysis(&mut self) -> (&A::Domain, &mut A) {
+ (&self.state, &mut self.results.borrow_mut().analysis)
}
/// Resets the cursor to hold the entry set for the given basic block.
@@ -97,7 +180,7 @@ where
#[cfg(debug_assertions)]
assert!(self.reachable_blocks.contains(block));
- self.state.clone_from(&self.results.borrow().entry_set_for_block(block));
+ self.state.clone_from(self.results.borrow().entry_set_for_block(block));
self.pos = CursorPosition::block_entry(block);
self.state_needs_reset = false;
}
@@ -186,7 +269,7 @@ where
)
};
- let analysis = &self.results.borrow().analysis;
+ let analysis = &mut self.results.borrow_mut().analysis;
let target_effect_index = effect.at_index(target.statement_index);
A::Direction::apply_effects_in_range(
@@ -205,8 +288,8 @@ where
///
/// This can be used, e.g., to apply the call return effect directly to the cursor without
/// creating an extra copy of the dataflow state.
- pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) {
- f(&self.results.borrow().analysis, &mut self.state);
+ pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
+ f(&mut self.results.borrow_mut().analysis, &mut self.state);
self.state_needs_reset = true;
}
}
@@ -215,7 +298,6 @@ impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
A: crate::GenKillAnalysis<'tcx>,
A::Domain: BitSetExt<A::Idx>,
- R: Borrow<Results<'tcx, A>>,
{
pub fn contains(&self, elem: A::Idx) -> bool {
self.get().contains(elem)
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index ba328e780..804b44a6b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -16,7 +16,7 @@ pub trait Direction {
///
/// `effects.start()` must precede or equal `effects.end()` in this direction.
fn apply_effects_in_range<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -25,7 +25,7 @@ pub trait Direction {
A: Analysis<'tcx>;
fn apply_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -33,7 +33,7 @@ pub trait Direction {
A: Analysis<'tcx>;
fn gen_kill_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -44,13 +44,13 @@ pub trait Direction {
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
- results: &R,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+ results: &mut R,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
) where
R: ResultsVisitable<'tcx, FlowState = F>;
fn join_state_into_successors_of<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
@@ -67,7 +67,7 @@ impl Direction for Backward {
const IS_FORWARD: bool = false;
fn apply_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -87,7 +87,7 @@ impl Direction for Backward {
}
fn gen_kill_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -107,7 +107,7 @@ impl Direction for Backward {
}
fn apply_effects_in_range<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -187,36 +187,36 @@ impl Direction for Backward {
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
- results: &R,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+ results: &mut R,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
) where
R: ResultsVisitable<'tcx, FlowState = F>,
{
results.reset_to_block_entry(state, block);
- vis.visit_block_end(&state, block_data, block);
+ vis.visit_block_end(results, &state, block_data, block);
// Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.reconstruct_before_terminator_effect(state, term, loc);
- vis.visit_terminator_before_primary_effect(state, term, loc);
+ vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.reconstruct_terminator_effect(state, term, loc);
- vis.visit_terminator_after_primary_effect(state, term, loc);
+ vis.visit_terminator_after_primary_effect(results, state, term, loc);
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index };
results.reconstruct_before_statement_effect(state, stmt, loc);
- vis.visit_statement_before_primary_effect(state, stmt, loc);
+ vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.reconstruct_statement_effect(state, stmt, loc);
- vis.visit_statement_after_primary_effect(state, stmt, loc);
+ vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}
- vis.visit_block_start(state, block_data, block);
+ vis.visit_block_start(results, state, block_data, block);
}
fn join_state_into_successors_of<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
_tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
@@ -319,7 +319,7 @@ impl Direction for Forward {
const IS_FORWARD: bool = true;
fn apply_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -339,7 +339,7 @@ impl Direction for Forward {
}
fn gen_kill_effects_in_block<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -359,7 +359,7 @@ impl Direction for Forward {
}
fn apply_effects_in_range<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &mir::BasicBlockData<'tcx>,
@@ -435,35 +435,35 @@ impl Direction for Forward {
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
- results: &R,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+ results: &mut R,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
) where
R: ResultsVisitable<'tcx, FlowState = F>,
{
results.reset_to_block_entry(state, block);
- vis.visit_block_start(state, block_data, block);
+ vis.visit_block_start(results, state, block_data, block);
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index };
results.reconstruct_before_statement_effect(state, stmt, loc);
- vis.visit_statement_before_primary_effect(state, stmt, loc);
+ vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.reconstruct_statement_effect(state, stmt, loc);
- vis.visit_statement_after_primary_effect(state, stmt, loc);
+ vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.reconstruct_before_terminator_effect(state, term, loc);
- vis.visit_terminator_before_primary_effect(state, term, loc);
+ vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.reconstruct_terminator_effect(state, term, loc);
- vis.visit_terminator_after_primary_effect(state, term, loc);
+ vis.visit_terminator_after_primary_effect(results, state, term, loc);
- vis.visit_block_end(state, block_data, block);
+ vis.visit_block_end(results, state, block_data, block);
}
fn join_state_into_successors_of<'tcx, A>(
- analysis: &A,
+ analysis: &mut A,
_tcx: TyCtxt<'tcx>,
_body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
@@ -502,15 +502,7 @@ impl Direction for Forward {
propagate(target, exit_state);
}
- Call {
- unwind,
- destination,
- target,
- func: _,
- args: _,
- from_hir_call: _,
- fn_span: _,
- } => {
+ Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => {
if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state);
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 3e8f792e6..c755d7588 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -5,7 +5,9 @@ use crate::errors::{
};
use crate::framework::BitSetExt;
+use std::borrow::Borrow;
use std::ffi::OsString;
+use std::marker::PhantomData;
use std::path::PathBuf;
use rustc_ast as ast;
@@ -22,54 +24,108 @@ use rustc_span::symbol::{sym, Symbol};
use super::fmt::DebugWithContext;
use super::graphviz;
use super::{
- visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
- ResultsCursor, ResultsVisitor,
+ visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
+ GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
+ ResultsVisitor,
};
+pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
+
/// A dataflow analysis that has converged to fixpoint.
-pub struct Results<'tcx, A>
+pub struct Results<'tcx, A, E = EntrySets<'tcx, A>>
where
A: Analysis<'tcx>,
{
pub analysis: A,
- pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
+ pub(super) entry_sets: E,
+ pub(super) _marker: PhantomData<&'tcx ()>,
}
-impl<'tcx, A> Results<'tcx, A>
+/// `Results` type with a cloned `Analysis` and borrowed entry sets.
+pub type ResultsCloned<'res, 'tcx, A> = Results<'tcx, A, &'res EntrySets<'tcx, A>>;
+
+impl<'tcx, A, E> Results<'tcx, A, E>
where
A: Analysis<'tcx>,
+ E: Borrow<EntrySets<'tcx, A>>,
{
/// Creates a `ResultsCursor` that can inspect these `Results`.
pub fn into_results_cursor<'mir>(
self,
body: &'mir mir::Body<'tcx>,
- ) -> ResultsCursor<'mir, 'tcx, A> {
+ ) -> ResultsCursor<'mir, 'tcx, A, Self> {
ResultsCursor::new(body, self)
}
/// Gets the dataflow state for the given block.
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
- &self.entry_sets[block]
+ &self.entry_sets.borrow()[block]
}
pub fn visit_with<'mir>(
- &self,
+ &mut self,
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
) {
visit_results(body, blocks, self, vis)
}
pub fn visit_reachable_with<'mir>(
- &self,
+ &mut self,
body: &'mir mir::Body<'tcx>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
) {
let blocks = mir::traversal::reachable(body);
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
}
}
+impl<'tcx, A> Results<'tcx, A>
+where
+ A: Analysis<'tcx>,
+{
+ /// Creates a `ResultsCursor` that can inspect these `Results`.
+ pub fn as_results_cursor<'a, 'mir>(
+ &'a mut self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsRefCursor<'a, 'mir, 'tcx, A> {
+ ResultsCursor::new(body, self)
+ }
+}
+impl<'tcx, A> Results<'tcx, A>
+where
+ A: Analysis<'tcx> + CloneAnalysis,
+{
+ /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+ pub fn clone_analysis(&self) -> ResultsCloned<'_, 'tcx, A> {
+ Results {
+ analysis: self.analysis.clone_analysis(),
+ entry_sets: &self.entry_sets,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Creates a `ResultsCursor` that can inspect these `Results`.
+ pub fn cloned_results_cursor<'mir>(
+ &self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> {
+ self.clone_analysis().into_results_cursor(body)
+ }
+}
+impl<'res, 'tcx, A> Results<'tcx, A, &'res EntrySets<'tcx, A>>
+where
+ A: Analysis<'tcx> + CloneAnalysis,
+{
+ /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+ pub fn reclone_analysis(&self) -> Self {
+ Results {
+ analysis: self.analysis.clone_analysis(),
+ entry_sets: self.entry_sets,
+ _marker: PhantomData,
+ }
+ }
+}
/// A solver for dataflow problems.
pub struct Engine<'a, 'tcx, A>
@@ -98,7 +154,7 @@ where
T: Idx,
{
/// Creates a new `Engine` to solve a gen-kill dataflow problem.
- pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
+ pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, mut analysis: A) -> Self {
// If there are no back-edges in the control-flow graph, we only ever need to apply the
// transfer function for each block exactly once (assuming that we process blocks in RPO).
//
@@ -114,7 +170,7 @@ where
for (block, block_data) in body.basic_blocks.iter_enumerated() {
let trans = &mut trans_for_block[block];
- A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
+ A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data);
}
let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
@@ -171,7 +227,13 @@ where
A::Domain: DebugWithContext<A>,
{
let Engine {
- analysis, body, mut entry_sets, tcx, apply_trans_for_block, pass_name, ..
+ mut analysis,
+ body,
+ mut entry_sets,
+ tcx,
+ apply_trans_for_block,
+ pass_name,
+ ..
} = self;
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
@@ -203,11 +265,13 @@ where
// Apply the block transfer function, using the cached one if it exists.
match &apply_trans_for_block {
Some(apply) => apply(bb, &mut state),
- None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
+ None => {
+ A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data)
+ }
}
A::Direction::join_state_into_successors_of(
- &analysis,
+ &mut analysis,
tcx,
body,
&mut state,
@@ -221,11 +285,13 @@ where
);
}
- let results = Results { analysis, entry_sets };
+ let mut results = Results { analysis, entry_sets, _marker: PhantomData };
- let res = write_graphviz_results(tcx, &body, &results, pass_name);
- if let Err(e) = res {
- error!("Failed to write graphviz dataflow results: {}", e);
+ if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
+ let res = write_graphviz_results(tcx, &body, &mut results, pass_name);
+ if let Err(e) = res {
+ error!("Failed to write graphviz dataflow results: {}", e);
+ }
}
results
@@ -235,11 +301,11 @@ where
// Graphviz
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
-/// `rustc_mir` attributes.
+/// `rustc_mir` attributes and `-Z dump-mir-dataflow`.
fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
- results: &Results<'tcx, A>,
+ results: &mut Results<'tcx, A>,
pass_name: Option<&'static str>,
) -> std::io::Result<()>
where
@@ -264,9 +330,7 @@ where
io::BufWriter::new(fs::File::create(&path)?)
}
- None if tcx.sess.opts.unstable_opts.dump_mir_dataflow
- && dump_enabled(tcx, A::NAME, def_id) =>
- {
+ None if dump_enabled(tcx, A::NAME, def_id) => {
create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 707729f8f..e331533c3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -1,6 +1,7 @@
//! A helpful diagram for debugging dataflow problems.
use std::borrow::Cow;
+use std::cell::RefCell;
use std::sync::OnceLock;
use std::{io, ops, str};
@@ -28,23 +29,27 @@ impl OutputStyle {
}
}
-pub struct Formatter<'a, 'tcx, A>
+pub struct Formatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
- body: &'a Body<'tcx>,
- results: &'a Results<'tcx, A>,
+ body: &'mir Body<'tcx>,
+ results: RefCell<&'res mut Results<'tcx, A>>,
style: OutputStyle,
reachable: BitSet<BasicBlock>,
}
-impl<'a, 'tcx, A> Formatter<'a, 'tcx, A>
+impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
- pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
+ pub fn new(
+ body: &'mir Body<'tcx>,
+ results: &'res mut Results<'tcx, A>,
+ style: OutputStyle,
+ ) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body);
- Formatter { body, results, style, reachable }
+ Formatter { body, results: results.into(), style, reachable }
}
}
@@ -64,7 +69,7 @@ fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
.collect()
}
-impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
+impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, '_, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -83,13 +88,14 @@ where
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
let mut label = Vec::new();
+ let mut results = self.results.borrow_mut();
let mut fmt = BlockFormatter {
- results: ResultsRefCursor::new(self.body, self.results),
+ results: results.as_results_cursor(self.body),
style: self.style,
bg: Background::Light,
};
- fmt.write_node_label(&mut label, self.body, *block).unwrap();
+ fmt.write_node_label(&mut label, *block).unwrap();
dot::LabelText::html(String::from_utf8(label).unwrap())
}
@@ -103,7 +109,7 @@ where
}
}
-impl<'a, 'tcx, A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
+impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
@@ -137,16 +143,16 @@ where
}
}
-struct BlockFormatter<'a, 'tcx, A>
+struct BlockFormatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
- results: ResultsRefCursor<'a, 'a, 'tcx, A>,
+ results: ResultsRefCursor<'res, 'mir, 'tcx, A>,
bg: Background,
style: OutputStyle,
}
-impl<'a, 'tcx, A> BlockFormatter<'a, 'tcx, A>
+impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -159,12 +165,7 @@ where
bg
}
- fn write_node_label(
- &mut self,
- w: &mut impl io::Write,
- body: &'a Body<'tcx>,
- block: BasicBlock,
- ) -> io::Result<()> {
+ fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> {
// Sample output:
// +-+-----------------------------------------------+
// A | bb4 |
@@ -215,11 +216,11 @@ where
self.write_row_with_full_state(w, "", "(on start)")?;
// D + E: Statement and terminator transfer functions
- self.write_statements_and_terminator(w, body, block)?;
+ self.write_statements_and_terminator(w, block)?;
// F: State at end of block
- let terminator = body[block].terminator();
+ let terminator = self.results.body()[block].terminator();
// Write the full dataflow state immediately after the terminator if it differs from the
// state at block entry.
@@ -389,10 +390,14 @@ where
fn write_statements_and_terminator(
&mut self,
w: &mut impl io::Write,
- body: &'a Body<'tcx>,
block: BasicBlock,
) -> io::Result<()> {
- let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style);
+ let diffs = StateDiffCollector::run(
+ self.results.body(),
+ block,
+ self.results.mut_results(),
+ self.style,
+ );
let mut diffs_before = diffs.before.map(|v| v.into_iter());
let mut diffs_after = diffs.after.into_iter();
@@ -401,7 +406,7 @@ where
if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
};
- for (i, statement) in body[block].statements.iter().enumerate() {
+ for (i, statement) in self.results.body()[block].statements.iter().enumerate() {
let statement_str = format!("{statement:?}");
let index_str = format!("{i}");
@@ -423,7 +428,7 @@ where
assert!(diffs_after.is_empty());
assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
- let terminator = body[block].terminator();
+ let terminator = self.results.body()[block].terminator();
let mut terminator_str = String::new();
terminator.kind.fmt_head(&mut terminator_str).unwrap();
@@ -492,29 +497,24 @@ where
}
}
-struct StateDiffCollector<'a, 'tcx, A>
-where
- A: Analysis<'tcx>,
-{
- analysis: &'a A,
- prev_state: A::Domain,
+struct StateDiffCollector<D> {
+ prev_state: D,
before: Option<Vec<String>>,
after: Vec<String>,
}
-impl<'a, 'tcx, A> StateDiffCollector<'a, 'tcx, A>
-where
- A: Analysis<'tcx>,
- A::Domain: DebugWithContext<A>,
-{
- fn run(
- body: &'a mir::Body<'tcx>,
+impl<D> StateDiffCollector<D> {
+ fn run<'tcx, A>(
+ body: &mir::Body<'tcx>,
block: BasicBlock,
- results: &'a Results<'tcx, A>,
+ results: &mut Results<'tcx, A>,
style: OutputStyle,
- ) -> Self {
+ ) -> Self
+ where
+ A: Analysis<'tcx, Domain = D>,
+ D: DebugWithContext<A>,
+ {
let mut collector = StateDiffCollector {
- analysis: &results.analysis,
prev_state: results.analysis.bottom_value(body),
after: vec![],
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
@@ -525,7 +525,7 @@ where
}
}
-impl<'a, 'tcx, A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
+impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -534,6 +534,7 @@ where
fn visit_block_start(
&mut self,
+ _results: &Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@@ -545,6 +546,7 @@ where
fn visit_block_end(
&mut self,
+ _results: &Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@@ -556,45 +558,49 @@ where
fn visit_statement_before_primary_effect(
&mut self,
+ results: &Results<'tcx, A>,
state: &Self::FlowState,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
- before.push(diff_pretty(state, &self.prev_state, self.analysis));
+ before.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}
fn visit_statement_after_primary_effect(
&mut self,
+ results: &Results<'tcx, A>,
state: &Self::FlowState,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
- self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
+ self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
fn visit_terminator_before_primary_effect(
&mut self,
+ results: &Results<'tcx, A>,
state: &Self::FlowState,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
- before.push(diff_pretty(state, &self.prev_state, self.analysis));
+ before.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}
fn visit_terminator_after_primary_effect(
&mut self,
+ results: &Results<'tcx, A>,
state: &Self::FlowState,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
- self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
+ self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index f2263007f..58df9b9a7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -45,9 +45,9 @@ pub mod graphviz;
pub mod lattice;
mod visitor;
-pub use self::cursor::{ResultsCursor, ResultsRefCursor};
+pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
pub use self::direction::{Backward, Direction, Forward};
-pub use self::engine::{Engine, Results};
+pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
@@ -146,7 +146,7 @@ pub trait AnalysisDomain<'tcx> {
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// Updates the current dataflow state with the effect of evaluating a statement.
fn apply_statement_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -159,7 +159,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_statement_effect`.
fn apply_before_statement_effect(
- &self,
+ &mut self,
_state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
_location: Location,
@@ -173,7 +173,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
/// initialized here.
fn apply_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -186,7 +186,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_terminator_effect`.
fn apply_before_terminator_effect(
- &self,
+ &mut self,
_state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
@@ -201,7 +201,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// This is separate from `apply_terminator_effect` to properly track state across unwind
/// edges.
fn apply_call_return_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -214,7 +214,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
///
/// By default, no effects happen.
fn apply_yield_resume_effect(
- &self,
+ &mut self,
_state: &mut Self::Domain,
_resume_block: BasicBlock,
_resume_place: mir::Place<'tcx>,
@@ -235,7 +235,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// engine doesn't need to clone the exit state for a block unless
/// `SwitchIntEdgeEffects::apply` is actually called.
fn apply_switch_int_edge_effects(
- &self,
+ &mut self,
_block: BasicBlock,
_discr: &mir::Operand<'tcx>,
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
@@ -269,6 +269,21 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
}
}
+/// Defines an `Analysis` which can be cloned for use in multiple `ResultsCursor`s or
+/// `ResultsVisitor`s. Note this need not be a full clone, only enough of one to be used with a new
+/// `ResultsCursor` or `ResultsVisitor`
+pub trait CloneAnalysis {
+ fn clone_analysis(&self) -> Self;
+}
+impl<'tcx, A> CloneAnalysis for A
+where
+ A: Analysis<'tcx> + Copy,
+{
+ fn clone_analysis(&self) -> Self {
+ *self
+ }
+}
+
/// A gen/kill dataflow problem.
///
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
@@ -282,7 +297,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_statement_effect`.
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -290,7 +305,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_before_statement_effect`.
fn before_statement_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_statement: &mir::Statement<'tcx>,
_location: Location,
@@ -299,7 +314,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_terminator_effect`.
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -307,7 +322,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_before_terminator_effect`.
fn before_terminator_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
@@ -318,7 +333,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_call_return_effect`.
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -326,7 +341,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_yield_resume_effect`.
fn yield_resume_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_resume_block: BasicBlock,
_resume_place: mir::Place<'tcx>,
@@ -335,7 +350,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_switch_int_edge_effects`.
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
- &self,
+ &mut self,
_block: BasicBlock,
_discr: &mir::Operand<'tcx>,
_edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -349,7 +364,7 @@ where
A::Domain: GenKill<A::Idx> + BitSetExt<A::Idx>,
{
fn apply_statement_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -358,7 +373,7 @@ where
}
fn apply_before_statement_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -367,7 +382,7 @@ where
}
fn apply_terminator_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -376,7 +391,7 @@ where
}
fn apply_before_terminator_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -387,7 +402,7 @@ where
/* Edge-specific effects */
fn apply_call_return_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -396,7 +411,7 @@ where
}
fn apply_yield_resume_effect(
- &self,
+ &mut self,
state: &mut A::Domain,
resume_block: BasicBlock,
resume_place: mir::Place<'tcx>,
@@ -405,7 +420,7 @@ where
}
fn apply_switch_int_edge_effects(
- &self,
+ &mut self,
block: BasicBlock,
discr: &mir::Operand<'tcx>,
edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 0fed305b9..cb0ec144e 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -40,7 +40,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
destination: dummy_place.clone(),
target: Some(mir::START_BLOCK),
unwind: mir::UnwindAction::Continue,
- from_hir_call: false,
+ call_source: mir::CallSource::Misc,
fn_span: DUMMY_SP,
},
);
@@ -54,7 +54,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
destination: dummy_place.clone(),
target: Some(mir::START_BLOCK),
unwind: mir::UnwindAction::Continue,
- from_hir_call: false,
+ call_source: mir::CallSource::Misc,
fn_span: DUMMY_SP,
},
);
@@ -179,7 +179,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
fn apply_statement_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
@@ -189,7 +189,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
}
fn apply_before_statement_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
@@ -199,7 +199,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
}
fn apply_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -209,7 +209,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
}
fn apply_before_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -219,7 +219,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
}
fn apply_call_return_effect(
- &self,
+ &mut self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
@@ -266,7 +266,8 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
let body = analysis.body;
let mut cursor =
- Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+ Results { entry_sets: analysis.mock_entry_sets(), analysis, _marker: PhantomData }
+ .into_results_cursor(body);
cursor.allow_unreachable();
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 75b4e150a..76a729827 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -1,16 +1,18 @@
+use std::borrow::Borrow;
+
use rustc_middle::mir::{self, BasicBlock, Location};
-use super::{Analysis, Direction, Results};
+use super::{Analysis, Direction, EntrySets, Results};
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
/// dataflow state at that location.
-pub fn visit_results<'mir, 'tcx, F, V>(
+pub fn visit_results<'mir, 'tcx, F, R>(
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
- results: &V,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+ results: &mut R,
+ vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
) where
- V: ResultsVisitable<'tcx, FlowState = F>,
+ R: ResultsVisitable<'tcx, FlowState = F>,
{
let mut state = results.new_flow_state(body);
@@ -22,15 +24,18 @@ pub fn visit_results<'mir, 'tcx, F, V>(
assert!(reachable_blocks.contains(block));
let block_data = &body[block];
- V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
+ R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
}
}
-pub trait ResultsVisitor<'mir, 'tcx> {
+/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
+/// visited.
+pub trait ResultsVisitor<'mir, 'tcx, R> {
type FlowState;
fn visit_block_start(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@@ -41,6 +46,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
/// its `statement_effect`.
fn visit_statement_before_primary_effect(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_statement: &'mir mir::Statement<'tcx>,
_location: Location,
@@ -51,6 +57,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
/// statement applied to `state`.
fn visit_statement_after_primary_effect(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_statement: &'mir mir::Statement<'tcx>,
_location: Location,
@@ -61,6 +68,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
/// its `terminator_effect`.
fn visit_terminator_before_primary_effect(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_terminator: &'mir mir::Terminator<'tcx>,
_location: Location,
@@ -73,6 +81,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
fn visit_terminator_after_primary_effect(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_terminator: &'mir mir::Terminator<'tcx>,
_location: Location,
@@ -81,6 +90,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
fn visit_block_end(
&mut self,
+ _results: &R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@@ -105,37 +115,38 @@ pub trait ResultsVisitable<'tcx> {
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
fn reconstruct_before_statement_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
statement: &mir::Statement<'tcx>,
location: Location,
);
fn reconstruct_statement_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
statement: &mir::Statement<'tcx>,
location: Location,
);
fn reconstruct_before_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
terminator: &mir::Terminator<'tcx>,
location: Location,
);
fn reconstruct_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
terminator: &mir::Terminator<'tcx>,
location: Location,
);
}
-impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
+impl<'tcx, A, E> ResultsVisitable<'tcx> for Results<'tcx, A, E>
where
A: Analysis<'tcx>,
+ E: Borrow<EntrySets<'tcx, A>>,
{
type FlowState = A::Domain;
@@ -146,11 +157,11 @@ where
}
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
- state.clone_from(&self.entry_set_for_block(block));
+ state.clone_from(self.entry_set_for_block(block));
}
fn reconstruct_before_statement_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
@@ -159,7 +170,7 @@ where
}
fn reconstruct_statement_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
@@ -168,7 +179,7 @@ where
}
fn reconstruct_before_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
@@ -177,7 +188,7 @@ where
}
fn reconstruct_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 92d30f254..b88ed32b6 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::*;
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
/// immovable generators.
+#[derive(Clone, Copy)]
pub struct MaybeBorrowedLocals;
impl MaybeBorrowedLocals {
@@ -36,7 +37,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -45,7 +46,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -54,7 +55,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
}
fn call_return_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 6ae6bdc17..9662c1977 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -21,6 +21,7 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi
/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
+#[derive(Clone, Copy)]
pub struct MaybeLiveLocals;
impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
@@ -43,7 +44,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
type Idx = Local;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -52,7 +53,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -61,7 +62,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -74,7 +75,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
}
fn yield_resume_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_resume_block: mir::BasicBlock,
resume_place: mir::Place<'tcx>,
@@ -215,6 +216,7 @@ impl DefUse {
/// This is basically written for dead store elimination and nothing else.
///
/// All of the caveats of `MaybeLiveLocals` apply.
+#[derive(Clone, Copy)]
pub struct MaybeTransitiveLiveLocals<'a> {
always_live: &'a BitSet<Local>,
}
@@ -247,7 +249,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
fn apply_statement_effect(
- &self,
+ &mut self,
trans: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -282,7 +284,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
}
fn apply_terminator_effect(
- &self,
+ &mut self,
trans: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -291,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
}
fn apply_call_return_effect(
- &self,
+ &mut self,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -304,7 +306,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
}
fn apply_yield_resume_effect(
- &self,
+ &mut self,
trans: &mut Self::Domain,
_resume_block: mir::BasicBlock,
resume_place: mir::Place<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 171db6965..98cec1c67 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -306,7 +306,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -329,7 +329,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -351,7 +351,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -372,7 +372,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
- &self,
+ &mut self,
block: mir::BasicBlock,
discr: &mir::Operand<'tcx>,
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -442,7 +442,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_statement: &mir::Statement<'tcx>,
location: Location,
@@ -456,7 +456,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -467,7 +467,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -488,7 +488,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
- &self,
+ &mut self,
block: mir::BasicBlock,
discr: &mir::Operand<'tcx>,
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -562,7 +562,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_statement: &mir::Statement<'tcx>,
location: Location,
@@ -573,7 +573,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -584,7 +584,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -627,7 +627,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
#[instrument(skip(self, trans), level = "debug")]
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
location: Location,
@@ -651,7 +651,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
#[instrument(skip(self, trans, _terminator), level = "debug")]
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -672,7 +672,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 463ce083a..666c8d50a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,10 +1,9 @@
pub use super::*;
-use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
+use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use std::borrow::Cow;
-use std::cell::RefCell;
#[derive(Clone)]
pub struct MaybeStorageLive<'a> {
@@ -17,6 +16,12 @@ impl<'a> MaybeStorageLive<'a> {
}
}
+impl crate::CloneAnalysis for MaybeStorageLive<'_> {
+ fn clone_analysis(&self) -> Self {
+ self.clone()
+ }
+}
+
impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
type Domain = BitSet<Local>;
@@ -43,7 +48,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
type Idx = Local;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
_: Location,
@@ -56,7 +61,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
}
fn terminator_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_: &mir::Terminator<'tcx>,
_: Location,
@@ -65,7 +70,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
}
fn call_return_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
@@ -110,7 +115,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
type Idx = Local;
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
_: Location,
@@ -123,7 +128,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
}
fn terminator_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_: &mir::Terminator<'tcx>,
_: Location,
@@ -132,7 +137,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
}
fn call_return_effect(
- &self,
+ &mut self,
_trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
@@ -141,28 +146,28 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
}
}
-type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
+type BorrowedLocalsResults<'res, 'mir, 'tcx> =
+ ResultsClonedCursor<'res, 'mir, 'tcx, MaybeBorrowedLocals>;
/// Dataflow analysis that determines whether each local requires storage at a
/// given location; i.e. whether its storage can go away without being observed.
-pub struct MaybeRequiresStorage<'mir, 'tcx> {
- body: &'mir Body<'tcx>,
- borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
+pub struct MaybeRequiresStorage<'res, 'mir, 'tcx> {
+ borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>,
}
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
- pub fn new(
- body: &'mir Body<'tcx>,
- borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
- ) -> Self {
- MaybeRequiresStorage {
- body,
- borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)),
- }
+impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> {
+ pub fn new(borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>) -> Self {
+ MaybeRequiresStorage { borrowed_locals }
+ }
+}
+
+impl crate::CloneAnalysis for MaybeRequiresStorage<'_, '_, '_> {
+ fn clone_analysis(&self) -> Self {
+ Self { borrowed_locals: self.borrowed_locals.new_cursor() }
}
}
-impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
type Domain = BitSet<Local>;
const NAME: &'static str = "requires_storage";
@@ -181,17 +186,17 @@ impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx
}
}
-impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
type Idx = Local;
fn before_statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
// If a place is borrowed in a statement, it needs storage for that statement.
- self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
+ self.borrowed_locals.mut_analysis().statement_effect(trans, stmt, loc);
match &stmt.kind {
StatementKind::StorageDead(l) => trans.kill(*l),
@@ -218,7 +223,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
fn statement_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_: &mir::Statement<'tcx>,
loc: Location,
@@ -229,13 +234,13 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
fn before_terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
loc: Location,
) {
// If a place is borrowed in a terminator, it needs storage for that terminator.
- self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
+ self.borrowed_locals.mut_analysis().terminator_effect(trans, terminator, loc);
match &terminator.kind {
TerminatorKind::Call { destination, .. } => {
@@ -282,7 +287,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
fn terminator_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
loc: Location,
@@ -321,7 +326,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
fn call_return_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
@@ -330,7 +335,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
fn yield_resume_effect(
- &self,
+ &mut self,
trans: &mut impl GenKill<Self::Idx>,
_resume_block: BasicBlock,
resume_place: mir::Place<'tcx>,
@@ -339,28 +344,28 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
}
}
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> {
/// Kill locals that are fully moved and have not been borrowed.
- fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
- let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
- visitor.visit_location(&self.body, loc);
+ fn check_for_move(&mut self, trans: &mut impl GenKill<Local>, loc: Location) {
+ let body = self.borrowed_locals.body();
+ let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals };
+ visitor.visit_location(body, loc);
}
}
-struct MoveVisitor<'a, 'mir, 'tcx, T> {
- borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
+struct MoveVisitor<'a, 'res, 'mir, 'tcx, T> {
+ borrowed_locals: &'a mut BorrowedLocalsResults<'res, 'mir, 'tcx>,
trans: &'a mut T,
}
-impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
+impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx, T>
where
T: GenKill<Local>,
{
fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
- let mut borrowed_locals = self.borrowed_locals.borrow_mut();
- borrowed_locals.seek_before_primary_effect(loc);
- if !borrowed_locals.contains(local) {
+ self.borrowed_locals.seek_before_primary_effect(loc);
+ if !self.borrowed_locals.contains(local) {
self.trans.kill(local);
}
}
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index fc4efb943..d43446bc5 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -27,9 +27,10 @@ pub use self::drop_flag_effects::{
on_lookup_result_bits,
};
pub use self::framework::{
- fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
- Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
- ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
+ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward,
+ CallReturnPlaces, CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis,
+ JoinSemiLattice, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
+ ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
};
use self::move_paths::MoveData;
@@ -42,7 +43,6 @@ pub mod impls;
pub mod move_paths;
pub mod rustc_peek;
pub mod storage;
-pub mod un_derefer;
pub mod value_analysis;
fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 096bc0acf..dc7e9ab3c 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,11 +1,10 @@
-use crate::move_paths::FxHashMap;
-use crate::un_derefer::UnDerefer;
use rustc_index::IndexVec;
use rustc_middle::mir::tcx::RvalueInitializationState;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
+use std::iter;
use std::mem;
use super::abs_domain::Lift;
@@ -21,7 +20,6 @@ struct MoveDataBuilder<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
data: MoveData<'tcx>,
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
- un_derefer: UnDerefer<'tcx>,
}
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -35,25 +33,29 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
tcx,
param_env,
errors: Vec::new(),
- un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() },
data: MoveData {
moves: IndexVec::new(),
loc_map: LocationMap::new(body),
rev_lookup: MovePathLookup {
locals: body
.local_decls
- .indices()
- .map(|i| {
- Self::new_move_path(
- &mut move_paths,
- &mut path_map,
- &mut init_path_map,
- None,
- Place::from(i),
+ .iter_enumerated()
+ .filter(|(_, l)| !l.is_deref_temp())
+ .map(|(i, _)| {
+ (
+ i,
+ Self::new_move_path(
+ &mut move_paths,
+ &mut path_map,
+ &mut init_path_map,
+ None,
+ Place::from(i),
+ ),
)
})
.collect(),
projections: Default::default(),
+ derefer_sidetable: Default::default(),
},
move_paths,
path_map,
@@ -98,13 +100,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
///
/// Maybe we should have separate "borrowck" and "moveck" modes.
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
- if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
- {
- return self.move_path_for(new_place);
- }
+ let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref());
debug!("lookup({:?})", place);
- let mut base = self.builder.data.rev_lookup.locals[place.local];
+ let mut base =
+ self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local);
// The move path index of the first union that we find. Once this is
// some we stop creating child move paths, since moves from unions
@@ -113,60 +113,55 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// from `*(u.f: &_)` isn't allowed.
let mut union_path = None;
- for (i, elem) in place.projection.iter().enumerate() {
- let proj_base = &place.projection[..i];
- let body = self.builder.body;
- let tcx = self.builder.tcx;
- let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
- match place_ty.kind() {
- ty::Ref(..) | ty::RawPtr(..) => {
- let proj = &place.projection[..i + 1];
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- BorrowedContent {
- target_place: Place {
- local: place.local,
- projection: tcx.mk_place_elems(proj),
+ for place in deref_chain.into_iter().chain(iter::once(place)) {
+ for (place_ref, elem) in place.as_ref().iter_projections() {
+ let body = self.builder.body;
+ let tcx = self.builder.tcx;
+ let place_ty = place_ref.ty(body, tcx).ty;
+ match place_ty.kind() {
+ ty::Ref(..) | ty::RawPtr(..) => {
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ BorrowedContent {
+ target_place: place_ref.project_deeper(&[elem], tcx),
},
- },
- ));
- }
- ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfTypeWithDestructor { container_ty: place_ty },
- ));
- }
- ty::Adt(adt, _) if adt.is_union() => {
- union_path.get_or_insert(base);
- }
- ty::Slice(_) => {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray {
- ty: place_ty,
- is_index: matches!(elem, ProjectionElem::Index(..)),
- },
- ));
- }
-
- ty::Array(..) => {
- if let ProjectionElem::Index(..) = elem {
+ ));
+ }
+ ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
return Err(MoveError::cannot_move_out_of(
self.loc,
- InteriorOfSliceOrArray { ty: place_ty, is_index: true },
+ InteriorOfTypeWithDestructor { container_ty: place_ty },
+ ));
+ }
+ ty::Adt(adt, _) if adt.is_union() => {
+ union_path.get_or_insert(base);
+ }
+ ty::Slice(_) => {
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ InteriorOfSliceOrArray {
+ ty: place_ty,
+ is_index: matches!(elem, ProjectionElem::Index(..)),
+ },
));
}
- }
- _ => {}
- };
+ ty::Array(..) => {
+ if let ProjectionElem::Index(..) = elem {
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ InteriorOfSliceOrArray { ty: place_ty, is_index: true },
+ ));
+ }
+ }
- if union_path.is_none() {
- base = self.add_move_path(base, elem, |tcx| Place {
- local: place.local,
- projection: tcx.mk_place_elems(&place.projection[..i + 1]),
- });
+ _ => {}
+ };
+
+ if union_path.is_none() {
+ base = self
+ .add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
+ }
}
}
@@ -207,10 +202,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
}
-pub type MoveDat<'tcx> = Result<
- (FxHashMap<Local, Place<'tcx>>, MoveData<'tcx>),
- (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>),
->;
+pub type MoveDat<'tcx> =
+ Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)>;
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
fn finalize(self) -> MoveDat<'tcx> {
@@ -226,11 +219,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
"done dumping moves"
});
- if self.errors.is_empty() {
- Ok((self.un_derefer.derefer_sidetable, self.data))
- } else {
- Err((self.data, self.errors))
- }
+ if self.errors.is_empty() { Ok(self.data) } else { Err((self.data, self.errors)) }
}
}
@@ -259,7 +248,7 @@ pub(super) fn gather_moves<'tcx>(
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
fn gather_args(&mut self) {
for arg in self.body.args_iter() {
- let path = self.data.rev_lookup.locals[arg];
+ let path = self.data.rev_lookup.find_local(arg);
let init = self.data.inits.push(Init {
path,
@@ -295,7 +284,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
assert!(place.projection.is_empty());
if self.builder.body.local_decls[place.local].is_deref_temp() {
- self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed);
+ self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed);
}
}
StatementKind::Assign(box (place, rval)) => {
@@ -317,7 +306,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::StorageLive(_) => {}
StatementKind::StorageDead(local) => {
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
- if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) {
+ if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) {
self.gather_move(Place::from(*local));
}
}
@@ -399,7 +388,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
destination,
target,
unwind: _,
- from_hir_call: _,
+ call_source: _,
fn_span: _,
} => {
self.gather_operand(func);
@@ -459,12 +448,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
fn gather_move(&mut self, place: Place<'tcx>) {
debug!("gather_move({:?}, {:?})", self.loc, place);
- if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
- {
- self.gather_move(new_place);
- return;
- }
-
if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
**place.projection
{
@@ -521,11 +504,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
debug!("gather_init({:?}, {:?})", self.loc, place);
- if let Some(new_place) = self.builder.un_derefer.derefer(place, self.builder.body) {
- self.gather_init(new_place.as_ref(), kind);
- return;
- }
-
let mut place = place;
// Check if we are assigning into a field of a union, if so, lookup the place
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index ab1a67153..aa901f66d 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,5 +1,5 @@
use crate::move_paths::builder::MoveDat;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
@@ -175,7 +175,7 @@ pub struct MoveData<'tcx> {
/// particular path being moved.)
pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>,
pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
- pub rev_lookup: MovePathLookup,
+ pub rev_lookup: MovePathLookup<'tcx>,
pub inits: IndexVec<InitIndex, Init>,
/// Each Location `l` is mapped to the Inits that are effects
/// of executing the code at `l`.
@@ -289,8 +289,8 @@ impl Init {
/// Tables mapping from a place to its MovePathIndex.
#[derive(Debug)]
-pub struct MovePathLookup {
- locals: IndexVec<Local, MovePathIndex>,
+pub struct MovePathLookup<'tcx> {
+ locals: FxIndexMap<Local, MovePathIndex>,
/// projections are made from a base-place and a projection
/// elem. The base-place will have a unique MovePathIndex; we use
@@ -299,6 +299,9 @@ pub struct MovePathLookup {
/// base-place). For the remaining lookup, we map the projection
/// elem to the associated MovePathIndex.
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
+
+ /// Maps `DerefTemp` locals to the `Place`s assigned to them.
+ derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
}
mod builder;
@@ -309,27 +312,59 @@ pub enum LookupResult {
Parent(Option<MovePathIndex>),
}
-impl MovePathLookup {
+impl<'tcx> MovePathLookup<'tcx> {
// Unlike the builder `fn move_path_for` below, this lookup
// alternative will *not* create a MovePath on the fly for an
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: PlaceRef<'_>) -> LookupResult {
- let mut result = self.locals[place.local];
+ let deref_chain = self.deref_chain(place);
- for elem in place.projection.iter() {
- if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
- result = subpath;
- } else {
+ let local = match deref_chain.first() {
+ Some(place) => place.local,
+ None => place.local,
+ };
+
+ let mut result = *self.locals.get(&local).unwrap_or_else(|| {
+ bug!("base local ({local:?}) of deref_chain should not be a deref temp")
+ });
+
+ // this needs to be a closure because `place` has a different lifetime than `prefix`'s places
+ let mut subpaths_for_place = |place: PlaceRef<'_>| {
+ for elem in place.projection.iter() {
+ if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
+ result = subpath;
+ } else {
+ return Some(result);
+ }
+ }
+ None
+ };
+
+ for place in deref_chain {
+ if let Some(result) = subpaths_for_place(place.as_ref()) {
return LookupResult::Parent(Some(result));
}
}
+ if let Some(result) = subpaths_for_place(place) {
+ return LookupResult::Parent(Some(result));
+ }
+
LookupResult::Exact(result)
}
pub fn find_local(&self, local: Local) -> MovePathIndex {
- self.locals[local]
+ let deref_chain = self.deref_chain(Place::from(local).as_ref());
+
+ let local = match deref_chain.last() {
+ Some(place) => place.local,
+ None => local,
+ };
+
+ *self.locals.get(&local).unwrap_or_else(|| {
+ bug!("base local ({local:?}) of deref_chain should not be a deref temp")
+ })
}
/// An enumerated iterator of `local`s and their associated
@@ -337,7 +372,22 @@ impl MovePathLookup {
pub fn iter_locals_enumerated(
&self,
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
- self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
+ self.locals.iter().map(|(&l, &idx)| (l, idx))
+ }
+
+ /// Returns the chain of places behind `DerefTemp` locals in `place`
+ pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> {
+ let mut prefix = Vec::new();
+ let mut local = place.local;
+
+ while let Some(&reffed) = self.derefer_sidetable.get(&local) {
+ prefix.insert(0, reffed);
+ local = reffed.local;
+ }
+
+ debug!("deref_chain({place:?}) = {prefix:?}");
+
+ prefix
}
}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 7cae68efb..156231c3a 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -17,7 +17,7 @@ use crate::impls::{
use crate::move_paths::{HasMoveData, MoveData};
use crate::move_paths::{LookupResult, MovePathIndex};
use crate::MoveDataParamEnv;
-use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
+use crate::{Analysis, JoinSemiLattice, ResultsCursor};
pub struct SanityCheck;
@@ -34,7 +34,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
}
let param_env = tcx.param_env(def_id);
- let (_, move_data) = MoveData::gather_moves(body, tcx, param_env).unwrap();
+ let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data, param_env };
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
@@ -42,7 +42,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
.into_engine(tcx, body)
.iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, body, &flow_inits);
+ sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
@@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
.into_engine(tcx, body)
.iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, body, &flow_uninits);
+ sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
@@ -58,13 +58,13 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
.into_engine(tcx, body)
.iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, body, &flow_def_inits);
+ sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, body, &flow_liveness);
+ sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
@@ -91,17 +91,14 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'tcx, A>(
tcx: TyCtxt<'tcx>,
- body: &Body<'tcx>,
- results: &Results<'tcx, A>,
+ mut cursor: ResultsCursor<'_, 'tcx, A>,
) where
A: RustcPeekAt<'tcx>,
{
- let def_id = body.source.def_id();
+ let def_id = cursor.body().source.def_id();
debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
- let mut cursor = ResultsCursor::new(body, results);
-
- let peek_calls = body.basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
+ let peek_calls = cursor.body().basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
});
@@ -132,8 +129,8 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
) => {
let loc = Location { block: bb, statement_index };
cursor.seek_before_primary_effect(loc);
- let state = cursor.get();
- results.analysis.peek_at(tcx, *place, state, call);
+ let (state, analysis) = cursor.get_with_analysis();
+ analysis.peek_at(tcx, *place, state, call);
}
_ => {
diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs
deleted file mode 100644
index 7e6e25cc6..000000000
--- a/compiler/rustc_mir_dataflow/src/un_derefer.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-/// Used for reverting changes made by `DerefSeparator`
-pub struct UnDerefer<'tcx> {
- pub tcx: TyCtxt<'tcx>,
- pub derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
-}
-
-impl<'tcx> UnDerefer<'tcx> {
- #[inline]
- pub fn derefer(&self, place: PlaceRef<'tcx>, body: &Body<'tcx>) -> Option<Place<'tcx>> {
- let reffed = self.derefer_sidetable.get(&place.local)?;
-
- let new_place = reffed.project_deeper(place.projection, self.tcx);
- if body.local_decls[new_place.local].is_deref_temp() {
- return self.derefer(new_place.as_ref(), body);
- }
- Some(new_place)
- }
-}
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index b74d06e5a..5693e5a4a 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -343,7 +343,7 @@ where
T: ValueAnalysis<'tcx>,
{
fn apply_statement_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
statement: &Statement<'tcx>,
_location: Location,
@@ -354,7 +354,7 @@ where
}
fn apply_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
terminator: &Terminator<'tcx>,
_location: Location,
@@ -365,7 +365,7 @@ where
}
fn apply_call_return_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
_block: BasicBlock,
return_places: crate::CallReturnPlaces<'_, 'tcx>,
@@ -376,7 +376,7 @@ where
}
fn apply_switch_int_edge_effects(
- &self,
+ &mut self,
_block: BasicBlock,
discr: &Operand<'tcx>,
apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,