summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_dataflow
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_mir_dataflow
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+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/Cargo.toml10
-rw-r--r--compiler/rustc_mir_dataflow/src/debuginfo.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/drop_flag_effects.rs83
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs18
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs230
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs56
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs165
15 files changed, 307 insertions, 311 deletions
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 4a296bb33..61664eb2a 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -3,13 +3,10 @@ name = "rustc_mir_dataflow"
version = "0.0.0"
edition = "2021"
-[lib]
-
[dependencies]
+# tidy-alphabetical-start
polonius-engine = "0.13.0"
regex = "1"
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
@@ -20,5 +17,8 @@ rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_serialize = { path = "../rustc_serialize" }
-rustc_target = { path = "../rustc_target" }
rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+# tidy-alphabetical-end
diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs
new file mode 100644
index 000000000..fd5e8cf29
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs
@@ -0,0 +1,20 @@
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+
+/// Return the set of locals that appear in debuginfo.
+pub fn debuginfo_locals(body: &Body<'_>) -> BitSet<Local> {
+ let mut visitor = DebuginfoLocals(BitSet::new_empty(body.local_decls.len()));
+ for debuginfo in body.var_debug_info.iter() {
+ visitor.visit_var_debug_info(debuginfo);
+ }
+ visitor.0
+}
+
+struct DebuginfoLocals(BitSet<Local>);
+
+impl Visitor<'_> for DebuginfoLocals {
+ fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) {
+ self.0.insert(local);
+ }
+}
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index 0d466bbe5..163d74cc9 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,6 +1,6 @@
use crate::elaborate_drops::DropFlagState;
use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
use rustc_target::abi::VariantIdx;
use super::indexes::MovePathIndex;
@@ -55,60 +55,6 @@ pub fn on_all_children_bits<'tcx, F>(
) where
F: FnMut(MovePathIndex),
{
- #[inline]
- fn is_terminal_path<'tcx>(
- tcx: TyCtxt<'tcx>,
- body: &Body<'tcx>,
- move_data: &MoveData<'tcx>,
- path: MovePathIndex,
- ) -> bool {
- let place = move_data.move_paths[path].place;
-
- // When enumerating the child fragments of a path, don't recurse into
- // paths (1.) past arrays, slices, and pointers, nor (2.) into a type
- // that implements `Drop`.
- //
- // Places behind references or arrays are not tracked by elaboration
- // and are always assumed to be initialized when accessible. As
- // references and indexes can be reseated, trying to track them can
- // only lead to trouble.
- //
- // Places behind ADT's with a Drop impl are not tracked by
- // elaboration since they can never have a drop-flag state that
- // differs from that of the parent with the Drop impl.
- //
- // In both cases, the contents can only be accessed if and only if
- // their parents are initialized. This implies for example that there
- // is no need to maintain separate drop flags to track such state.
- //
- // FIXME: we have to do something for moving slice patterns.
- let ty = place.ty(body, tcx).ty;
- match ty.kind() {
- ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
- place, ty
- );
- true
- }
- ty::Array(..) => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
- place, ty
- );
- false
- }
- ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
- place, ty
- );
- true
- }
- _ => false,
- }
- }
-
fn on_all_children_bits<'tcx, F>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -120,10 +66,6 @@ pub fn on_all_children_bits<'tcx, F>(
{
each_child(move_path_index);
- if is_terminal_path(tcx, body, move_data, move_path_index) {
- return;
- }
-
let mut next_child_index = move_data.move_paths[move_path_index].first_child;
while let Some(child_index) = next_child_index {
on_all_children_bits(tcx, body, move_data, child_index, each_child);
@@ -133,29 +75,6 @@ pub fn on_all_children_bits<'tcx, F>(
on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
}
-pub fn on_all_drop_children_bits<'tcx, F>(
- tcx: TyCtxt<'tcx>,
- body: &Body<'tcx>,
- ctxt: &MoveDataParamEnv<'tcx>,
- path: MovePathIndex,
- mut each_child: F,
-) where
- F: FnMut(MovePathIndex),
-{
- on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| {
- let place = &ctxt.move_data.move_paths[path].place;
- let ty = place.ty(body, tcx).ty;
- debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty);
-
- let erased_ty = tcx.erase_regions(ty);
- if erased_ty.needs_drop(tcx, ctxt.param_env) {
- each_child(child);
- } else {
- debug!("on_all_drop_children_bits - skipping")
- }
- })
-}
-
pub fn drop_flag_effects_for_function_entry<'tcx, F>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index c9991e499..25ba67a63 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -860,13 +860,13 @@ where
let ty = self.place_ty(self.place);
match ty.kind() {
ty::Closure(_, args) => self.open_drop_for_tuple(&args.as_closure().upvar_tys()),
- // Note that `elaborate_drops` only drops the upvars of a generator,
+ // Note that `elaborate_drops` only drops the upvars of a coroutine,
// and this is ok because `open_drop` here can only be reached
- // within that own generator's resume function.
+ // within that own coroutine's resume function.
// This should only happen for the self argument on the resume function.
- // It effectively only contains upvars until the generator transformation runs.
- // See librustc_body/transform/generator.rs for more details.
- ty::Generator(_, args, _) => self.open_drop_for_tuple(&args.as_generator().upvar_tys()),
+ // It effectively only contains upvars until the coroutine transformation runs.
+ // See librustc_body/transform/coroutine.rs for more details.
+ ty::Coroutine(_, args, _) => self.open_drop_for_tuple(&args.as_coroutine().upvar_tys()),
ty::Tuple(fields) => self.open_drop_for_tuple(fields),
ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index bdddaaebc..c12ccba1e 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -267,7 +267,7 @@ where
mir::TerminatorKind::Yield { resume, resume_arg, .. } => {
self.write_row(w, "", "(on yield resume)", |this, w, fmt| {
- let state_on_generator_drop = this.results.get().clone();
+ let state_on_coroutine_drop = this.results.get().clone();
this.results.apply_custom_effect(|analysis, state| {
analysis.apply_call_return_effect(
state,
@@ -283,7 +283,7 @@ where
fmt = fmt,
diff = diff_pretty(
this.results.get(),
- &state_on_generator_drop,
+ &state_on_coroutine_drop,
this.results.analysis()
),
)
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index ce30c642f..5020a1cf0 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -48,7 +48,7 @@ mod visitor;
pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
pub use self::direction::{Backward, Direction, Forward};
pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
-pub use self::lattice::{JoinSemiLattice, MaybeReachable, MeetSemiLattice};
+pub use self::lattice::{JoinSemiLattice, MaybeReachable};
pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
/// Analysis domains are all bitsets of various kinds. This trait holds
@@ -114,7 +114,7 @@ pub trait AnalysisDomain<'tcx> {
//
// FIXME: For backward dataflow analyses, the initial state should be applied to every basic
// block where control flow could exit the MIR body (e.g., those terminated with `return` or
- // `resume`). It's not obvious how to handle `yield` points in generators, however.
+ // `resume`). It's not obvious how to handle `yield` points in coroutines, however.
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
}
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index f6398c8d0..01acc380f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -10,7 +10,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
///
/// 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.
+/// immovable coroutines.
#[derive(Clone, Copy)]
pub struct MaybeBorrowedLocals;
@@ -141,7 +141,7 @@ where
| TerminatorKind::Call { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::GeneratorDrop
+ | TerminatorKind::CoroutineDrop
| TerminatorKind::Goto { .. }
| TerminatorKind::InlineAsm { .. }
| TerminatorKind::UnwindResume
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index e6d383d62..c968e7aea 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -10,7 +10,7 @@ use crate::framework::SwitchIntEdgeEffects;
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::on_lookup_result_bits;
use crate::MoveDataParamEnv;
-use crate::{drop_flag_effects, on_all_children_bits, on_all_drop_children_bits};
+use crate::{drop_flag_effects, on_all_children_bits};
use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable};
/// `MaybeInitializedPlaces` tracks all places that might be
@@ -72,7 +72,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
) -> bool {
if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
let mut maybe_live = false;
- on_all_drop_children_bits(self.tcx, self.body, self.mdpe, path, |child| {
+ on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
maybe_live |= state.contains(child);
});
!maybe_live
@@ -690,9 +690,13 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
if let mir::StatementKind::StorageDead(local) = stmt.kind {
// End inits for StorageDead, so that an immutable variable can
// be reinitialized on the next iteration of the loop.
- let move_path_index = rev_lookup.find_local(local);
- debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]);
- trans.kill_all(init_path_map[move_path_index].iter().copied());
+ if let Some(move_path_index) = rev_lookup.find_local(local) {
+ debug!(
+ "clears the ever initialized status of {:?}",
+ init_path_map[move_path_index]
+ );
+ trans.kill_all(init_path_map[move_path_index].iter().copied());
+ }
}
}
@@ -763,9 +767,9 @@ fn switch_on_enum_discriminant<'mir, 'tcx>(
ty::Adt(def, _) => return Some((*discriminated, *def)),
// `Rvalue::Discriminant` is also used to get the active yield point for a
- // generator, but we do not need edge-specific effects in that case. This may
+ // coroutine, but we do not need edge-specific effects in that case. This may
// change in the future.
- ty::Generator(..) => return None,
+ ty::Coroutine(..) => return None,
t => bug!("`discriminant` called on unexpected type {:?}", t),
}
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 664703795..bdfb6a6ff 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -98,7 +98,7 @@ where
{
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context {
- // The resume place is evaluated and assigned to only after generator resumes, so its
+ // The resume place is evaluated and assigned to only after coroutine resumes, so its
// effect is handled separately in `call_resume_effect`.
return;
}
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 94d6eb67d..5a58e3af8 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -268,7 +268,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
// Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
// that is that a `yield` will return from the function, and `resume_arg` is written
- // only when the generator is later resumed. Unlike `Call`, this doesn't require the
+ // only when the coroutine is later resumed. Unlike `Call`, this doesn't require the
// place to have storage *before* the yield, only after.
TerminatorKind::Yield { .. } => {}
@@ -296,7 +296,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
| TerminatorKind::Drop { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::GeneratorDrop
+ | TerminatorKind::CoroutineDrop
| TerminatorKind::Goto { .. }
| TerminatorKind::UnwindResume
| TerminatorKind::Return
@@ -333,7 +333,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
| TerminatorKind::Drop { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::GeneratorDrop
+ | TerminatorKind::CoroutineDrop
| TerminatorKind::Goto { .. }
| TerminatorKind::UnwindResume
| TerminatorKind::Return
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 0cdbee19d..eea0e030e 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -23,8 +23,7 @@ use rustc_span::symbol::{sym, Symbol};
pub use self::drop_flag_effects::{
drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
- move_path_children_matching, on_all_children_bits, on_all_drop_children_bits,
- on_lookup_result_bits,
+ move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
};
pub use self::framework::{
fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward,
@@ -35,6 +34,7 @@ pub use self::framework::{
use self::move_paths::MoveData;
+pub mod debuginfo;
pub mod drop_flag_effects;
pub mod elaborate_drops;
mod errors;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 7a5b3585d..ccf3dc794 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,58 +1,66 @@
use rustc_index::IndexVec;
-use rustc_middle::mir::tcx::RvalueInitializationState;
+use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState};
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use smallvec::{smallvec, SmallVec};
use std::mem;
use super::abs_domain::Lift;
-use super::IllegalMoveOriginKind::*;
-use super::{Init, InitIndex, InitKind, InitLocation, LookupResult, MoveError};
+use super::{Init, InitIndex, InitKind, InitLocation, LookupResult};
use super::{
LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
};
-struct MoveDataBuilder<'a, 'tcx> {
+struct MoveDataBuilder<'a, 'tcx, F> {
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
data: MoveData<'tcx>,
- errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
+ filter: F,
}
-impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
- fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
+ fn new(
+ body: &'a Body<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ filter: F,
+ ) -> Self {
let mut move_paths = IndexVec::new();
let mut path_map = IndexVec::new();
let mut init_path_map = IndexVec::new();
+ let locals = body
+ .local_decls
+ .iter_enumerated()
+ .map(|(i, l)| {
+ if l.is_deref_temp() {
+ return None;
+ }
+ if filter(l.ty) {
+ Some(new_move_path(
+ &mut move_paths,
+ &mut path_map,
+ &mut init_path_map,
+ None,
+ Place::from(i),
+ ))
+ } else {
+ None
+ }
+ })
+ .collect();
+
MoveDataBuilder {
body,
tcx,
param_env,
- errors: Vec::new(),
data: MoveData {
moves: IndexVec::new(),
loc_map: LocationMap::new(body),
rev_lookup: MovePathLookup {
- locals: body
- .local_decls
- .iter_enumerated()
- .map(|(i, l)| {
- if l.is_deref_temp() {
- MovePathIndex::MAX
- } else {
- Self::new_move_path(
- &mut move_paths,
- &mut path_map,
- &mut init_path_map,
- None,
- Place::from(i),
- )
- }
- })
- .collect(),
+ locals,
projections: Default::default(),
un_derefer: Default::default(),
},
@@ -62,35 +70,42 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
init_loc_map: LocationMap::new(body),
init_path_map,
},
+ filter,
}
}
+}
- fn new_move_path(
- move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
- path_map: &mut IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
- init_path_map: &mut IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
- parent: Option<MovePathIndex>,
- place: Place<'tcx>,
- ) -> MovePathIndex {
- let move_path =
- move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place });
+fn new_move_path<'tcx>(
+ move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
+ path_map: &mut IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
+ init_path_map: &mut IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
+ parent: Option<MovePathIndex>,
+ place: Place<'tcx>,
+) -> MovePathIndex {
+ let move_path =
+ move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place });
+
+ if let Some(parent) = parent {
+ let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path));
+ move_paths[move_path].next_sibling = next_sibling;
+ }
- if let Some(parent) = parent {
- let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path));
- move_paths[move_path].next_sibling = next_sibling;
- }
+ let path_map_ent = path_map.push(smallvec![]);
+ assert_eq!(path_map_ent, move_path);
- let path_map_ent = path_map.push(smallvec![]);
- assert_eq!(path_map_ent, move_path);
+ let init_path_map_ent = init_path_map.push(smallvec![]);
+ assert_eq!(init_path_map_ent, move_path);
- let init_path_map_ent = init_path_map.push(smallvec![]);
- assert_eq!(init_path_map_ent, move_path);
+ move_path
+}
- move_path
- }
+enum MovePathResult {
+ Path(MovePathIndex),
+ Union(MovePathIndex),
+ Error,
}
-impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
+impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
/// This creates a MovePath for a given place, returning an `MovePathError`
/// if that place can't be moved from.
///
@@ -98,11 +113,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
/// problematic for borrowck.
///
/// Maybe we should have separate "borrowck" and "moveck" modes.
- fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
+ fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult {
let data = &mut self.builder.data;
debug!("lookup({:?})", place);
- let mut base = data.rev_lookup.find_local(place.local);
+ let Some(mut base) = data.rev_lookup.find_local(place.local) else {
+ return MovePathResult::Error;
+ };
// 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
@@ -118,12 +135,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
match elem {
ProjectionElem::Deref => 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),
- },
- ));
+ return MovePathResult::Error;
}
ty::Adt(adt, _) => {
if !adt.is_box() {
@@ -143,8 +155,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Alias(_, _)
@@ -159,16 +171,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
ProjectionElem::Field(_, _) => match place_ty.kind() {
ty::Adt(adt, _) => {
if adt.has_dtor(tcx) {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfTypeWithDestructor { container_ty: place_ty },
- ));
+ return MovePathResult::Error;
}
if adt.is_union() {
union_path.get_or_insert(base);
}
}
- ty::Closure(_, _) | ty::Generator(_, _, _) | ty::Tuple(_) => (),
+ ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (),
ty::Bool
| ty::Char
| ty::Int(_)
@@ -183,7 +192,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Alias(_, _)
| ty::Param(_)
@@ -197,33 +206,15 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
match place_ty.kind() {
ty::Slice(_) => {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray {
- ty: place_ty,
- is_index: matches!(elem, ProjectionElem::Index(..)),
- },
- ));
+ return MovePathResult::Error;
}
ty::Array(_, _) => (),
_ => bug!("Unexpected type {:#?}", place_ty.is_array()),
}
}
ProjectionElem::Index(_) => match place_ty.kind() {
- ty::Array(..) => {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray { ty: place_ty, is_index: true },
- ));
- }
- ty::Slice(_) => {
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray {
- ty: place_ty,
- is_index: matches!(elem, ProjectionElem::Index(..)),
- },
- ));
+ ty::Array(..) | ty::Slice(_) => {
+ return MovePathResult::Error;
}
_ => bug!("Unexpected type {place_ty:#?}"),
},
@@ -235,11 +226,15 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _) => (),
}
+ let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
+ if !(self.builder.filter)(elem_ty) {
+ return MovePathResult::Error;
+ }
if union_path.is_none() {
// inlined from add_move_path because of a borrowck conflict with the iterator
base =
*data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| {
- MoveDataBuilder::new_move_path(
+ new_move_path(
&mut data.move_paths,
&mut data.path_map,
&mut data.init_path_map,
@@ -252,9 +247,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
if let Some(base) = union_path {
// Move out of union - always move the entire union.
- Err(MoveError::UnionMove { path: base })
+ MovePathResult::Union(base)
} else {
- Ok(base)
+ MovePathResult::Path(base)
}
}
@@ -270,13 +265,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
..
} = self.builder;
*rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || {
- MoveDataBuilder::new_move_path(
- move_paths,
- path_map,
- init_path_map,
- Some(base),
- mk_place(*tcx),
- )
+ new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx))
})
}
@@ -287,11 +276,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, '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> {
+impl<'a, 'tcx, F> MoveDataBuilder<'a, 'tcx, F> {
+ fn finalize(self) -> MoveData<'tcx> {
debug!("{}", {
debug!("moves for {:?}:", self.body.span);
for (j, mo) in self.data.moves.iter_enumerated() {
@@ -304,7 +290,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
"done dumping moves"
});
- if self.errors.is_empty() { Ok(self.data) } else { Err((self.data, self.errors)) }
+ self.data
}
}
@@ -312,8 +298,9 @@ pub(super) fn gather_moves<'tcx>(
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
-) -> MoveDat<'tcx> {
- let mut builder = MoveDataBuilder::new(body, tcx, param_env);
+ filter: impl Fn(Ty<'tcx>) -> bool,
+) -> MoveData<'tcx> {
+ let mut builder = MoveDataBuilder::new(body, tcx, param_env, filter);
builder.gather_args();
@@ -330,20 +317,20 @@ pub(super) fn gather_moves<'tcx>(
builder.finalize()
}
-impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
fn gather_args(&mut self) {
for arg in self.body.args_iter() {
- let path = self.data.rev_lookup.find_local(arg);
+ if let Some(path) = self.data.rev_lookup.find_local(arg) {
+ let init = self.data.inits.push(Init {
+ path,
+ kind: InitKind::Deep,
+ location: InitLocation::Argument(arg),
+ });
- let init = self.data.inits.push(Init {
- path,
- kind: InitKind::Deep,
- location: InitLocation::Argument(arg),
- });
+ debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg);
- debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg);
-
- self.data.init_path_map[path].push(init);
+ self.data.init_path_map[path].push(init);
+ }
}
}
@@ -358,12 +345,12 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
}
}
-struct Gatherer<'b, 'a, 'tcx> {
- builder: &'b mut MoveDataBuilder<'a, 'tcx>,
+struct Gatherer<'b, 'a, 'tcx, F> {
+ builder: &'b mut MoveDataBuilder<'a, 'tcx, F>,
loc: Location,
}
-impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
+impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
match &stmt.kind {
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
@@ -454,7 +441,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| TerminatorKind::Return
| TerminatorKind::UnwindResume
| TerminatorKind::UnwindTerminate(_)
- | TerminatorKind::GeneratorDrop
+ | TerminatorKind::CoroutineDrop
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. } => {}
@@ -546,13 +533,12 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
let base_place =
Place { local: place.local, projection: self.builder.tcx.mk_place_elems(base) };
let base_path = match self.move_path_for(base_place) {
- Ok(path) => path,
- Err(MoveError::UnionMove { path }) => {
+ MovePathResult::Path(path) => path,
+ MovePathResult::Union(path) => {
self.record_move(place, path);
return;
}
- Err(error @ MoveError::IllegalMove { .. }) => {
- self.builder.errors.push((base_place, error));
+ MovePathResult::Error => {
return;
}
};
@@ -572,10 +558,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
} else {
match self.move_path_for(place) {
- Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
- Err(error @ MoveError::IllegalMove { .. }) => {
- self.builder.errors.push((place, error));
+ MovePathResult::Path(path) | MovePathResult::Union(path) => {
+ self.record_move(place, path)
}
+ MovePathResult::Error => {}
};
}
}
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index 0c7aa6676..7ab1a9ed0 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,4 +1,3 @@
-use crate::move_paths::builder::MoveDat;
use crate::un_derefer::UnDerefer;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::{IndexSlice, IndexVec};
@@ -291,7 +290,7 @@ impl Init {
/// Tables mapping from a place to its MovePathIndex.
#[derive(Debug)]
pub struct MovePathLookup<'tcx> {
- locals: IndexVec<Local, MovePathIndex>,
+ locals: IndexVec<Local, Option<MovePathIndex>>,
/// projections are made from a base-place and a projection
/// elem. The base-place will have a unique MovePathIndex; we use
@@ -318,7 +317,9 @@ impl<'tcx> MovePathLookup<'tcx> {
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult {
- let mut result = self.find_local(place.local);
+ let Some(mut result) = self.find_local(place.local) else {
+ return LookupResult::Parent(None);
+ };
for (_, elem) in self.un_derefer.iter_projections(place) {
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
@@ -332,7 +333,7 @@ impl<'tcx> MovePathLookup<'tcx> {
}
#[inline]
- pub fn find_local(&self, local: Local) -> MovePathIndex {
+ pub fn find_local(&self, local: Local) -> Option<MovePathIndex> {
self.locals[local]
}
@@ -340,46 +341,8 @@ impl<'tcx> MovePathLookup<'tcx> {
/// `MovePathIndex`es.
pub fn iter_locals_enumerated(
&self,
- ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
- self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
- }
-}
-
-#[derive(Debug)]
-pub struct IllegalMoveOrigin<'tcx> {
- pub location: Location,
- pub kind: IllegalMoveOriginKind<'tcx>,
-}
-
-#[derive(Debug)]
-pub enum IllegalMoveOriginKind<'tcx> {
- /// Illegal move due to attempt to move from behind a reference.
- BorrowedContent {
- /// The place the reference refers to: if erroneous code was trying to
- /// move from `(*x).f` this will be `*x`.
- target_place: Place<'tcx>,
- },
-
- /// Illegal move due to attempt to move from field of an ADT that
- /// implements `Drop`. Rust maintains invariant that all `Drop`
- /// ADT's remain fully-initialized so that user-defined destructor
- /// can safely read from all of the ADT's fields.
- InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> },
-
- /// Illegal move due to attempt to move out of a slice or array.
- InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool },
-}
-
-#[derive(Debug)]
-pub enum MoveError<'tcx> {
- IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
- UnionMove { path: MovePathIndex },
-}
-
-impl<'tcx> MoveError<'tcx> {
- fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self {
- let origin = IllegalMoveOrigin { location, kind };
- MoveError::IllegalMove { cannot_move_out_of: origin }
+ ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + '_ {
+ self.locals.iter_enumerated().filter_map(|(l, &idx)| Some((l, idx?)))
}
}
@@ -388,8 +351,9 @@ impl<'tcx> MoveData<'tcx> {
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
- ) -> MoveDat<'tcx> {
- builder::gather_moves(body, tcx, param_env)
+ filter: impl Fn(Ty<'tcx>) -> bool,
+ ) -> MoveData<'tcx> {
+ builder::gather_moves(body, tcx, param_env, filter)
}
/// For the move path `mpi`, returns the root local variable (if any) that starts the path.
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 1ebb59b3a..d3dce641b 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -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, |_| true);
let mdpe = MoveDataParamEnv { move_data, param_env };
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 83766f311..025d2ddfd 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -274,7 +274,7 @@ pub trait ValueAnalysis<'tcx> {
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Assert { .. }
- | TerminatorKind::GeneratorDrop
+ | TerminatorKind::CoroutineDrop
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => {
// These terminators have no effect on the analysis.
@@ -463,7 +463,19 @@ impl<V: Clone> Clone for State<V> {
}
}
-impl<V: Clone + HasTop + HasBottom> State<V> {
+impl<V: Clone> State<V> {
+ pub fn new(init: V, map: &Map) -> State<V> {
+ let values = IndexVec::from_elem_n(init, map.value_count);
+ State(StateData::Reachable(values))
+ }
+
+ pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
+ match self.0 {
+ StateData::Unreachable => true,
+ StateData::Reachable(ref values) => values.iter().all(f),
+ }
+ }
+
pub fn is_reachable(&self) -> bool {
matches!(&self.0, StateData::Reachable(_))
}
@@ -472,7 +484,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
self.0 = StateData::Unreachable;
}
- pub fn flood_all(&mut self) {
+ pub fn flood_all(&mut self)
+ where
+ V: HasTop,
+ {
self.flood_all_with(V::TOP)
}
@@ -481,28 +496,52 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
values.raw.fill(value);
}
+ /// Assign `value` to all places that are contained in `place` or may alias one.
pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
- let StateData::Reachable(values) = &mut self.0 else { return };
- map.for_each_aliasing_place(place, None, &mut |vi| {
- values[vi] = value.clone();
- });
+ self.flood_with_tail_elem(place, None, map, value)
}
- pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
+ /// Assign `TOP` to all places that are contained in `place` or may alias one.
+ pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map)
+ where
+ V: HasTop,
+ {
self.flood_with(place, map, V::TOP)
}
+ /// Assign `value` to the discriminant of `place` and all places that may alias it.
pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
- let StateData::Reachable(values) = &mut self.0 else { return };
- map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |vi| {
- values[vi] = value.clone();
- });
+ self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value)
}
- pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) {
+ /// Assign `TOP` to the discriminant of `place` and all places that may alias it.
+ pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map)
+ where
+ V: HasTop,
+ {
self.flood_discr_with(place, map, V::TOP)
}
+ /// This method is the most general version of the `flood_*` method.
+ ///
+ /// Assign `value` on the given place and all places that may alias it. In particular, when
+ /// the given place has a variant downcast, we invoke the function on all the other variants.
+ ///
+ /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
+ /// as such.
+ pub fn flood_with_tail_elem(
+ &mut self,
+ place: PlaceRef<'_>,
+ tail_elem: Option<TrackElem>,
+ map: &Map,
+ value: V,
+ ) {
+ let StateData::Reachable(values) = &mut self.0 else { return };
+ map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
+ values[vi] = value.clone();
+ });
+ }
+
/// Low-level method that assigns to a place.
/// This does nothing if the place is not tracked.
///
@@ -553,7 +592,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
}
/// Helper method to interpret `target = result`.
- pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
+ pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+ where
+ V: HasTop,
+ {
self.flood(target, map);
if let Some(target) = map.find(target) {
self.insert_idx(target, result, map);
@@ -561,36 +603,93 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
}
/// Helper method for assignments to a discriminant.
- pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
+ pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+ where
+ V: HasTop,
+ {
self.flood_discr(target, map);
if let Some(target) = map.find_discr(target) {
self.insert_idx(target, result, map);
}
}
+ /// Retrieve the value stored for a place, or `None` if it is not tracked.
+ pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+ let place = map.find(place)?;
+ self.try_get_idx(place, map)
+ }
+
+ /// Retrieve the discriminant stored for a place, or `None` if it is not tracked.
+ pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+ let place = map.find_discr(place)?;
+ self.try_get_idx(place, map)
+ }
+
+ /// Retrieve the slice length stored for a place, or `None` if it is not tracked.
+ pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+ let place = map.find_len(place)?;
+ self.try_get_idx(place, map)
+ }
+
+ /// Retrieve the value stored for a place index, or `None` if it is not tracked.
+ pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
+ match &self.0 {
+ StateData::Reachable(values) => {
+ map.places[place].value_index.map(|v| values[v].clone())
+ }
+ StateData::Unreachable => None,
+ }
+ }
+
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
- pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V {
- map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP)
+ ///
+ /// This method returns ⊥ if the place is tracked and the state is unreachable.
+ pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V
+ where
+ V: HasBottom + HasTop,
+ {
+ match &self.0 {
+ StateData::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
+ // Because this is unreachable, we can return any value we want.
+ StateData::Unreachable => V::BOTTOM,
+ }
}
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
- pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V {
- match map.find_discr(place) {
- Some(place) => self.get_idx(place, map),
- None => V::TOP,
+ ///
+ /// This method returns ⊥ the current state is unreachable.
+ pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V
+ where
+ V: HasBottom + HasTop,
+ {
+ match &self.0 {
+ StateData::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
+ // Because this is unreachable, we can return any value we want.
+ StateData::Unreachable => V::BOTTOM,
}
}
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
- pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V {
- match map.find_len(place) {
- Some(place) => self.get_idx(place, map),
- None => V::TOP,
+ ///
+ /// This method returns ⊥ the current state is unreachable.
+ pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V
+ where
+ V: HasBottom + HasTop,
+ {
+ match &self.0 {
+ StateData::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP),
+ // Because this is unreachable, we can return any value we want.
+ StateData::Unreachable => V::BOTTOM,
}
}
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
- pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
+ ///
+ /// This method returns ⊥ the current state is unreachable.
+ pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
+ where
+ V: HasBottom + HasTop,
+ {
match &self.0 {
StateData::Reachable(values) => {
map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)
@@ -685,8 +784,10 @@ impl Map {
// `elem1` is either `Some(Variant(i))` or `None`.
while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() {
// The user requires a bound on the number of created values.
- if let Some(value_limit) = value_limit && self.value_count >= value_limit {
- break
+ if let Some(value_limit) = value_limit
+ && self.value_count >= value_limit
+ {
+ break;
}
// Create a place for this projection.
@@ -717,7 +818,9 @@ impl Map {
// Trim useless places.
for opt_place in self.locals.iter_mut() {
- if let Some(place) = *opt_place && self.inner_values[place].is_empty() {
+ if let Some(place) = *opt_place
+ && self.inner_values[place].is_empty()
+ {
*opt_place = None;
}
}
@@ -772,7 +875,7 @@ impl Map {
assert!(old.is_none());
// Allocate a value slot since it doesn't have one.
- assert!( self.places[len].value_index.is_none() );
+ assert!(self.places[len].value_index.is_none());
self.places[len].value_index = Some(self.value_count.into());
self.value_count += 1;
}
@@ -911,7 +1014,7 @@ impl Map {
) {
for sibling in self.children(parent) {
let elem = self.places[sibling].proj_elem;
- // Only invalidate variants and discriminant. Fields (for generators) are not
+ // Only invalidate variants and discriminant. Fields (for coroutines) are not
// invalidated by assignment to a variant.
if let Some(TrackElem::Variant(..) | TrackElem::Discriminant) = elem
// Only invalidate the other variants, the current one is fine.