1use std::debug_assert_matches;
2use std::fmt::{Debug, Formatter};
3use std::ops::Range;
4
5use rustc_abi::{FieldIdx, VariantIdx};
6use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
7use rustc_data_structures::stack::ensure_sufficient_stack;
8use rustc_index::IndexVec;
9use rustc_index::bit_set::DenseBitSet;
10use rustc_middle::mir::visit::{PlaceContext, Visitor};
11use rustc_middle::mir::*;
12use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized};
13use tracing::debug;
14
15use crate::JoinSemiLattice;
16use crate::lattice::{HasBottom, HasTop};
17
18impl ::std::fmt::Debug for PlaceIndex {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("{0}", self.as_u32()))
}
}rustc_index::newtype_index!(
19 pub struct PlaceIndex {}
24);
25
26impl ::std::fmt::Debug for ValueIndex {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("{0}", self.as_u32()))
}
}rustc_index::newtype_index!(
27 pub struct ValueIndex {}
29);
30
31#[derive(#[automatically_derived]
impl<V: ::core::cmp::PartialEq> ::core::cmp::PartialEq for StateData<V> {
#[inline]
fn eq(&self, other: &StateData<V>) -> bool {
self.bottom == other.bottom && self.map == other.map
}
}PartialEq, #[automatically_derived]
impl<V: ::core::cmp::Eq> ::core::cmp::Eq for StateData<V> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<V>;
let _: ::core::cmp::AssertParamIsEq<FxHashMap<ValueIndex, V>>;
}
}Eq, #[automatically_derived]
impl<V: ::core::fmt::Debug> ::core::fmt::Debug for StateData<V> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "StateData",
"bottom", &self.bottom, "map", &&self.map)
}
}Debug)]
33pub struct StateData<V> {
34 bottom: V,
35 map: FxHashMap<ValueIndex, V>,
37}
38
39impl<V: HasBottom> StateData<V> {
40 fn new() -> StateData<V> {
41 StateData { bottom: V::BOTTOM, map: FxHashMap::default() }
42 }
43
44 fn get(&self, idx: ValueIndex) -> &V {
45 self.map.get(&idx).unwrap_or(&self.bottom)
46 }
47
48 fn insert(&mut self, idx: ValueIndex, elem: V) {
49 if elem.is_bottom() {
50 self.map.remove(&idx);
51 } else {
52 self.map.insert(idx, elem);
53 }
54 }
55}
56
57impl<V: Clone> Clone for StateData<V> {
58 fn clone(&self) -> Self {
59 StateData { bottom: self.bottom.clone(), map: self.map.clone() }
60 }
61
62 fn clone_from(&mut self, source: &Self) {
63 self.map.clone_from(&source.map)
64 }
65}
66
67impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
68 fn join(&mut self, other: &Self) -> bool {
69 let mut changed = false;
70 #[allow(rustc::potential_query_instability)]
71 for (i, v) in other.map.iter() {
72 match self.map.entry(*i) {
73 StdEntry::Vacant(e) => {
74 e.insert(v.clone());
75 changed = true
76 }
77 StdEntry::Occupied(e) => changed |= e.into_mut().join(v),
78 }
79 }
80 changed
81 }
82}
83
84#[derive(#[automatically_derived]
impl<V: ::core::cmp::PartialEq> ::core::cmp::PartialEq for State<V> {
#[inline]
fn eq(&self, other: &State<V>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(State::Reachable(__self_0), State::Reachable(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl<V: ::core::cmp::Eq> ::core::cmp::Eq for State<V> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<StateData<V>>;
}
}Eq, #[automatically_derived]
impl<V: ::core::fmt::Debug> ::core::fmt::Debug for State<V> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
State::Unreachable =>
::core::fmt::Formatter::write_str(f, "Unreachable"),
State::Reachable(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Reachable", &__self_0),
}
}
}Debug)]
95pub enum State<V> {
96 Unreachable,
97 Reachable(StateData<V>),
98}
99
100impl<V: Clone> Clone for State<V> {
101 fn clone(&self) -> Self {
102 match self {
103 Self::Reachable(x) => Self::Reachable(x.clone()),
104 Self::Unreachable => Self::Unreachable,
105 }
106 }
107
108 fn clone_from(&mut self, source: &Self) {
109 match (&mut *self, source) {
110 (Self::Reachable(x), Self::Reachable(y)) => {
111 x.clone_from(&y);
112 }
113 _ => *self = source.clone(),
114 }
115 }
116}
117
118impl<V: Clone + HasBottom> State<V> {
119 pub fn new_reachable() -> State<V> {
120 State::Reachable(StateData::new())
121 }
122
123 pub fn is_reachable(&self) -> bool {
124 #[allow(non_exhaustive_omitted_patterns)] match self {
State::Reachable(_) => true,
_ => false,
}matches!(self, State::Reachable(_))
125 }
126
127 pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) {
129 self.flood_with_tail_elem(place, None, map, value)
130 }
131
132 pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map<'_>)
134 where
135 V: HasTop,
136 {
137 self.flood_with(place, map, V::TOP)
138 }
139
140 fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) {
142 self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value)
143 }
144
145 pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map<'_>)
147 where
148 V: HasTop,
149 {
150 self.flood_discr_with(place, map, V::TOP)
151 }
152
153 fn flood_with_tail_elem(
161 &mut self,
162 place: PlaceRef<'_>,
163 tail_elem: Option<TrackElem>,
164 map: &Map<'_>,
165 value: V,
166 ) {
167 let State::Reachable(values) = self else { return };
168 map.for_each_aliasing_place(place, tail_elem, &mut |vi| values.insert(vi, value.clone()));
169 }
170
171 fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map<'_>) {
176 match result {
177 ValueOrPlace::Value(value) => self.insert_value_idx(target, value, map),
178 ValueOrPlace::Place(source) => self.insert_place_idx(target, source, map),
179 }
180 }
181
182 pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map<'_>) {
187 let State::Reachable(values) = self else { return };
188 if let Some(value_index) = map.places[target].value_index {
189 values.insert(value_index, value)
190 }
191 }
192
193 pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) {
201 let State::Reachable(values) = self else { return };
202 map.for_each_value_pair(target, source, &mut |target, source| {
203 values.insert(target, values.get(source).clone());
204 });
205 }
206
207 pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map<'_>)
209 where
210 V: HasTop,
211 {
212 self.flood(target, map);
213 if let Some(target) = map.find(target) {
214 self.insert_idx(target, result, map);
215 }
216 }
217
218 pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map<'_>)
220 where
221 V: HasTop,
222 {
223 self.flood_discr(target, map);
224 if let Some(target) = map.find_discr(target) {
225 self.insert_idx(target, result, map);
226 }
227 }
228
229 fn try_get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option<V> {
231 let place = map.find(place)?;
232 self.try_get_idx(place, map)
233 }
234
235 fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option<V> {
237 let place = map.find_discr(place)?;
238 self.try_get_idx(place, map)
239 }
240
241 fn try_get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> Option<V> {
243 match self {
244 State::Reachable(values) => {
245 map.places[place].value_index.map(|v| values.get(v).clone())
246 }
247 State::Unreachable => None,
248 }
249 }
250
251 pub fn get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V
255 where
256 V: HasBottom + HasTop,
257 {
258 match self {
259 State::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
260 State::Unreachable => V::BOTTOM,
262 }
263 }
264
265 pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V
269 where
270 V: HasBottom + HasTop,
271 {
272 match self {
273 State::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
274 State::Unreachable => V::BOTTOM,
276 }
277 }
278
279 pub fn get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> V
283 where
284 V: HasBottom + HasTop,
285 {
286 match self {
287 State::Reachable(values) => {
288 map.places[place].value_index.map(|v| values.get(v).clone()).unwrap_or(V::TOP)
289 }
290 State::Unreachable => {
291 V::BOTTOM
293 }
294 }
295 }
296}
297
298impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
299 fn join(&mut self, other: &Self) -> bool {
300 match (&mut *self, other) {
301 (_, State::Unreachable) => false,
302 (State::Unreachable, _) => {
303 *self = other.clone();
304 true
305 }
306 (State::Reachable(this), State::Reachable(other)) => this.join(other),
307 }
308 }
309}
310
311#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Map<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["locals", "projections", "places", "value_count", "mode",
"inner_values", "inner_values_buffer"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.locals, &self.projections, &self.places,
&self.value_count, &self.mode, &self.inner_values,
&&self.inner_values_buffer];
::core::fmt::Formatter::debug_struct_fields_finish(f, "Map", names,
values)
}
}Debug)]
318pub struct Map<'tcx> {
319 locals: IndexVec<Local, Option<PlaceIndex>>,
320 projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>,
321 places: IndexVec<PlaceIndex, PlaceInfo<'tcx>>,
322 value_count: usize,
323 mode: PlaceCollectionMode,
324 inner_values: IndexVec<PlaceIndex, Range<usize>>,
326 inner_values_buffer: Vec<ValueIndex>,
327}
328
329#[derive(#[automatically_derived]
impl ::core::marker::Copy for PlaceCollectionMode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PlaceCollectionMode {
#[inline]
fn clone(&self) -> PlaceCollectionMode {
let _: ::core::clone::AssertParamIsClone<Option<usize>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for PlaceCollectionMode {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
PlaceCollectionMode::Full { value_limit: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Full",
"value_limit", &__self_0),
PlaceCollectionMode::OnDemand =>
::core::fmt::Formatter::write_str(f, "OnDemand"),
}
}
}Debug)]
330pub enum PlaceCollectionMode {
331 Full { value_limit: Option<usize> },
332 OnDemand,
333}
334
335impl<'tcx> Map<'tcx> {
336 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("new",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(341u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["mode"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&mode)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Self = loop {};
return __tracing_attr_fake_return;
}
{
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_dataflow/src/value_analysis.rs:343",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(343u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["def_id"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&body.source.def_id())
as &dyn Value))])
});
} else { ; }
};
let capacity = 4 * body.local_decls.len();
let mut map =
Self {
locals: IndexVec::from_elem(None, &body.local_decls),
projections: FxHashMap::default(),
places: IndexVec::with_capacity(capacity),
value_count: 0,
mode,
inner_values: IndexVec::new(),
inner_values_buffer: Vec::new(),
};
map.register_locals(tcx, body);
match mode {
PlaceCollectionMode::Full { value_limit } => {
map.collect_places(tcx, body);
map.propagate_assignments(tcx, body);
map.create_values(tcx, body, value_limit);
map.trim_useless_places();
}
PlaceCollectionMode::OnDemand => {}
}
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_dataflow/src/value_analysis.rs:364",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(364u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("registered {0} places ({1} nodes in total)",
map.value_count, map.places.len()) as &dyn Value))])
});
} else { ; }
};
map
}
}
}#[tracing::instrument(level = "trace", skip(tcx, body))]
342 pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, mode: PlaceCollectionMode) -> Self {
343 tracing::trace!(def_id=?body.source.def_id());
344 let capacity = 4 * body.local_decls.len();
345 let mut map = Self {
346 locals: IndexVec::from_elem(None, &body.local_decls),
347 projections: FxHashMap::default(),
348 places: IndexVec::with_capacity(capacity),
349 value_count: 0,
350 mode,
351 inner_values: IndexVec::new(),
352 inner_values_buffer: Vec::new(),
353 };
354 map.register_locals(tcx, body);
355 match mode {
356 PlaceCollectionMode::Full { value_limit } => {
357 map.collect_places(tcx, body);
358 map.propagate_assignments(tcx, body);
359 map.create_values(tcx, body, value_limit);
360 map.trim_useless_places();
361 }
362 PlaceCollectionMode::OnDemand => {}
363 }
364 debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len());
365 map
366 }
367
368 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("register_locals",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(369u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let exclude = excluded_locals(body);
for (local, decl) in body.local_decls.iter_enumerated() {
if exclude.contains(local) { continue; }
if decl.ty.is_async_drop_in_place_coroutine(tcx) { continue; }
if true {
if !self.locals[local].is_none() {
::core::panicking::panic("assertion failed: self.locals[local].is_none()")
};
};
let place = self.places.push(PlaceInfo::new(decl.ty, None));
self.locals[local] = Some(place);
}
}
}
}#[tracing::instrument(level = "trace", skip(self, tcx, body))]
370 fn register_locals(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
371 let exclude = excluded_locals(body);
372
373 for (local, decl) in body.local_decls.iter_enumerated() {
375 if exclude.contains(local) {
376 continue;
377 }
378 if decl.ty.is_async_drop_in_place_coroutine(tcx) {
379 continue;
380 }
381
382 debug_assert!(self.locals[local].is_none());
384 let place = self.places.push(PlaceInfo::new(decl.ty, None));
385 self.locals[local] = Some(place);
386 }
387 }
388
389 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("collect_places",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(390u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let mut collector = PlaceCollector { tcx, body, map: self };
collector.visit_body(body);
}
}
}#[tracing::instrument(level = "trace", skip(self, tcx, body))]
391 fn collect_places(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
392 let mut collector = PlaceCollector { tcx, body, map: self };
393 collector.visit_body(body);
394 }
395
396 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("propagate_assignments",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(404u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let mut assignments = FxIndexSet::default();
for bbdata in body.basic_blocks.iter() {
for stmt in bbdata.statements.iter() {
let Some((lhs, rhs)) =
stmt.kind.as_assign() else { continue };
match rhs {
Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs), _) |
Rvalue::CopyForDeref(rhs) => {
let Some(lhs) =
self.register_place_and_discr(tcx, body,
*lhs) else { continue; };
let Some(rhs) =
self.register_place_and_discr(tcx, body,
*rhs) else { continue; };
assignments.insert((lhs, rhs));
}
Rvalue::Aggregate(kind, fields) => {
let Some(mut lhs) =
self.register_place_and_discr(tcx, body,
*lhs) else { continue; };
match **kind {
AggregateKind::Adt(_, _, _, _, Some(_)) => continue,
AggregateKind::Adt(_, variant, _, _, None) => {
let ty = self.places[lhs].ty;
if ty.is_enum() {
lhs =
self.register_place_index(ty, lhs,
TrackElem::Variant(variant));
}
}
AggregateKind::RawPtr(..) | AggregateKind::Array(_) |
AggregateKind::Tuple | AggregateKind::Closure(..) |
AggregateKind::Coroutine(..) |
AggregateKind::CoroutineClosure(..) => {}
}
for (index, field) in fields.iter_enumerated() {
if let Some(rhs) = field.place() &&
let Some(rhs) =
self.register_place_and_discr(tcx, body, rhs) {
let lhs =
self.register_place_index(self.places[rhs].ty, lhs,
TrackElem::Field(index));
assignments.insert((lhs, rhs));
}
}
}
_ => {}
}
}
}
let mut num_places = 0;
while num_places < self.places.len() {
num_places = self.places.len();
for assign in 0.. {
let Some(&(lhs, rhs)) =
assignments.get_index(assign) else { break };
let mut child = self.places[lhs].first_child;
while let Some(lhs_child) = child {
let PlaceInfo { ty, proj_elem, next_sibling, .. } =
self.places[lhs_child];
let rhs_child =
self.register_place_index(ty, rhs,
proj_elem.expect("child is not a projection"));
assignments.insert((lhs_child, rhs_child));
child = next_sibling;
}
let mut child = self.places[rhs].first_child;
while let Some(rhs_child) = child {
let PlaceInfo { ty, proj_elem, next_sibling, .. } =
self.places[rhs_child];
let lhs_child =
self.register_place_index(ty, lhs,
proj_elem.expect("child is not a projection"));
assignments.insert((lhs_child, rhs_child));
child = next_sibling;
}
}
}
}
}
}#[tracing::instrument(level = "trace", skip(self, tcx, body))]
405 fn propagate_assignments(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
406 let mut assignments = FxIndexSet::default();
408
409 for bbdata in body.basic_blocks.iter() {
410 for stmt in bbdata.statements.iter() {
411 let Some((lhs, rhs)) = stmt.kind.as_assign() else { continue };
412 match rhs {
413 Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs), _)
414 | Rvalue::CopyForDeref(rhs) => {
415 let Some(lhs) = self.register_place_and_discr(tcx, body, *lhs) else {
416 continue;
417 };
418 let Some(rhs) = self.register_place_and_discr(tcx, body, *rhs) else {
419 continue;
420 };
421 assignments.insert((lhs, rhs));
422 }
423 Rvalue::Aggregate(kind, fields) => {
424 let Some(mut lhs) = self.register_place_and_discr(tcx, body, *lhs) else {
425 continue;
426 };
427 match **kind {
428 AggregateKind::Adt(_, _, _, _, Some(_)) => continue,
430 AggregateKind::Adt(_, variant, _, _, None) => {
431 let ty = self.places[lhs].ty;
432 if ty.is_enum() {
433 lhs = self.register_place_index(
434 ty,
435 lhs,
436 TrackElem::Variant(variant),
437 );
438 }
439 }
440 AggregateKind::RawPtr(..)
441 | AggregateKind::Array(_)
442 | AggregateKind::Tuple
443 | AggregateKind::Closure(..)
444 | AggregateKind::Coroutine(..)
445 | AggregateKind::CoroutineClosure(..) => {}
446 }
447 for (index, field) in fields.iter_enumerated() {
448 if let Some(rhs) = field.place()
449 && let Some(rhs) = self.register_place_and_discr(tcx, body, rhs)
450 {
451 let lhs = self.register_place_index(
452 self.places[rhs].ty,
453 lhs,
454 TrackElem::Field(index),
455 );
456 assignments.insert((lhs, rhs));
457 }
458 }
459 }
460 _ => {}
461 }
462 }
463 }
464
465 let mut num_places = 0;
468 while num_places < self.places.len() {
469 num_places = self.places.len();
470
471 for assign in 0.. {
472 let Some(&(lhs, rhs)) = assignments.get_index(assign) else { break };
473
474 let mut child = self.places[lhs].first_child;
476 while let Some(lhs_child) = child {
477 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[lhs_child];
478 let rhs_child = self.register_place_index(
479 ty,
480 rhs,
481 proj_elem.expect("child is not a projection"),
482 );
483 assignments.insert((lhs_child, rhs_child));
484 child = next_sibling;
485 }
486
487 let mut child = self.places[rhs].first_child;
489 while let Some(rhs_child) = child {
490 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[rhs_child];
491 let lhs_child = self.register_place_index(
492 ty,
493 lhs,
494 proj_elem.expect("child is not a projection"),
495 );
496 assignments.insert((lhs_child, rhs_child));
497 child = next_sibling;
498 }
499 }
500 }
501 }
502
503 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("create_values",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(504u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["value_limit"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value_limit)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if true {
{
match self.mode {
PlaceCollectionMode::Full { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"PlaceCollectionMode::Full { .. }",
::core::option::Option::None);
}
}
};
};
let typing_env = body.typing_env(tcx);
for place_info in self.places.iter_mut() {
if let Some(value_limit) = value_limit &&
self.value_count >= value_limit {
break;
}
if let Ok(ty) =
tcx.try_normalize_erasing_regions(typing_env,
Unnormalized::new_wip(place_info.ty)) {
place_info.ty = ty;
}
if !place_info.value_index.is_none() {
::core::panicking::panic("assertion failed: place_info.value_index.is_none()")
};
if let Ok(layout) =
tcx.layout_of(typing_env.as_query_input(place_info.ty)) &&
layout.backend_repr.is_scalar() {
place_info.value_index = Some(self.value_count.into());
self.value_count += 1;
}
}
self.inner_values_buffer = Vec::with_capacity(self.value_count);
self.inner_values = IndexVec::from_elem(0..0, &self.places);
for local in body.local_decls.indices() {
if let Some(place) = self.locals[local] {
self.cache_preorder_invoke(place);
}
}
}
}
}#[tracing::instrument(level = "trace", skip(self, tcx, body))]
505 fn create_values(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) {
506 debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. });
507 let typing_env = body.typing_env(tcx);
508 for place_info in self.places.iter_mut() {
509 if let Some(value_limit) = value_limit
511 && self.value_count >= value_limit
512 {
513 break;
514 }
515
516 if let Ok(ty) =
517 tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(place_info.ty))
518 {
519 place_info.ty = ty;
520 }
521
522 assert!(place_info.value_index.is_none());
524 if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(place_info.ty))
525 && layout.backend_repr.is_scalar()
526 {
527 place_info.value_index = Some(self.value_count.into());
528 self.value_count += 1;
529 }
530 }
531
532 self.inner_values_buffer = Vec::with_capacity(self.value_count);
536 self.inner_values = IndexVec::from_elem(0..0, &self.places);
537 for local in body.local_decls.indices() {
538 if let Some(place) = self.locals[local] {
539 self.cache_preorder_invoke(place);
540 }
541 }
542 }
543
544 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("trim_useless_places",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(545u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if true {
{
match self.mode {
PlaceCollectionMode::Full { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"PlaceCollectionMode::Full { .. }",
::core::option::Option::None);
}
}
};
};
for opt_place in self.locals.iter_mut() {
if let Some(place) = *opt_place &&
self.inner_values[place].is_empty() {
*opt_place = None;
}
}
#[allow(rustc::potential_query_instability)]
self.projections.retain(|_, child|
!self.inner_values[*child].is_empty());
}
}
}#[tracing::instrument(level = "trace", skip(self))]
546 fn trim_useless_places(&mut self) {
547 debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. });
548 for opt_place in self.locals.iter_mut() {
549 if let Some(place) = *opt_place
550 && self.inner_values[place].is_empty()
551 {
552 *opt_place = None;
553 }
554 }
555 #[allow(rustc::potential_query_instability)]
556 self.projections.retain(|_, child| !self.inner_values[*child].is_empty());
557 }
558
559 x;#[tracing::instrument(level = "trace", skip(self), ret)]
560 pub fn register_place_index(
561 &mut self,
562 ty: Ty<'tcx>,
563 base: PlaceIndex,
564 elem: TrackElem,
565 ) -> PlaceIndex {
566 *self.projections.entry((base, elem)).or_insert_with(|| {
567 let next = self.places.push(PlaceInfo::new(ty, Some(elem)));
568 self.places[next].next_sibling = self.places[base].first_child;
569 self.places[base].first_child = Some(next);
570 next
571 })
572 }
573
574 x;#[tracing::instrument(level = "trace", skip(self, tcx, body), ret)]
575 pub fn register_place(
576 &mut self,
577 tcx: TyCtxt<'tcx>,
578 body: &Body<'tcx>,
579 place: Place<'tcx>,
580 tail: Option<TrackElem>,
581 ) -> Option<PlaceIndex> {
582 let mut place_index = self.locals[place.local]?;
584 let mut ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
585 tracing::trace!(?place_index, ?ty);
586
587 for proj in place.projection {
588 let track_elem = proj.try_into().ok()?;
589 ty = ty.projection_ty(tcx, proj);
590 place_index = self.register_place_index(ty.ty, place_index, track_elem);
591 tracing::trace!(?proj, ?place_index, ?ty);
592 }
593
594 if let Some(tail) = tail {
595 let ty = match tail {
596 TrackElem::Discriminant => ty.ty.discriminant_ty(tcx),
597 TrackElem::Variant(..) | TrackElem::Field(..) => todo!(),
598 TrackElem::DerefLen => tcx.types.usize,
599 };
600 place_index = self.register_place_index(ty, place_index, tail);
601 }
602
603 Some(place_index)
604 }
605
606 x;#[tracing::instrument(level = "trace", skip(self, tcx, body), ret)]
607 fn register_place_and_discr(
608 &mut self,
609 tcx: TyCtxt<'tcx>,
610 body: &Body<'tcx>,
611 place: Place<'tcx>,
612 ) -> Option<PlaceIndex> {
613 let place = self.register_place(tcx, body, place, None)?;
614 let ty = self.places[place].ty;
615
616 if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind()
617 && let ty::Slice(..) = ref_ty.kind()
618 {
619 self.register_place_index(tcx.types.usize, place, TrackElem::DerefLen);
620 } else if ty.is_enum() {
621 let discriminant_ty = ty.discriminant_ty(tcx);
622 self.register_place_index(discriminant_ty, place, TrackElem::Discriminant);
623 }
624
625 Some(place)
626 }
627
628 x;#[tracing::instrument(level = "trace", skip(self, tcx, typing_env), ret)]
629 pub fn register_value(
630 &mut self,
631 tcx: TyCtxt<'tcx>,
632 typing_env: ty::TypingEnv<'tcx>,
633 place: PlaceIndex,
634 ) -> Option<ValueIndex> {
635 let place_info = &mut self.places[place];
636 if let Some(value) = place_info.value_index {
637 return Some(value);
638 }
639
640 if let Ok(ty) =
641 tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(place_info.ty))
642 {
643 place_info.ty = ty;
644 }
645
646 if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(place_info.ty))
648 && layout.backend_repr.is_scalar()
649 {
650 place_info.value_index = Some(self.value_count.into());
651 self.value_count += 1;
652 }
653
654 place_info.value_index
655 }
656
657 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("register_copy_tree",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(657u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["source", "target"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if let Some(source_value) = self.places[source].value_index {
let target_value =
*self.places[target].value_index.get_or_insert_with(||
{
let value_index = self.value_count.into();
self.value_count += 1;
value_index
});
f(source_value, target_value)
}
let mut source_child_iter = self.places[source].first_child;
while let Some(source_child) = source_child_iter {
source_child_iter = self.places[source_child].next_sibling;
let source_info = &self.places[source_child];
let source_ty = source_info.ty;
let source_elem = source_info.proj_elem.unwrap();
let target_child =
self.register_place_index(source_ty, target, source_elem);
self.register_copy_tree(source_child, target_child, f);
}
}
}
}#[tracing::instrument(level = "trace", skip(self, f))]
658 pub fn register_copy_tree(
659 &mut self,
660 source: PlaceIndex,
662 target: PlaceIndex,
664 f: &mut impl FnMut(ValueIndex, ValueIndex),
665 ) {
666 if let Some(source_value) = self.places[source].value_index {
667 let target_value = *self.places[target].value_index.get_or_insert_with(|| {
668 let value_index = self.value_count.into();
669 self.value_count += 1;
670 value_index
671 });
672 f(source_value, target_value)
673 }
674
675 let mut source_child_iter = self.places[source].first_child;
677 while let Some(source_child) = source_child_iter {
678 source_child_iter = self.places[source_child].next_sibling;
679
680 let source_info = &self.places[source_child];
682 let source_ty = source_info.ty;
683 let source_elem = source_info.proj_elem.unwrap();
684 let target_child = self.register_place_index(source_ty, target, source_elem);
685 self.register_copy_tree(source_child, target_child, f);
686 }
687 }
688
689 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("cache_preorder_invoke",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(691u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["root"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&root)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if true {
{
match self.mode {
PlaceCollectionMode::Full { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"PlaceCollectionMode::Full { .. }",
::core::option::Option::None);
}
}
};
};
let start = self.inner_values_buffer.len();
if let Some(vi) = self.places[root].value_index {
self.inner_values_buffer.push(vi);
}
let mut next_child = self.places[root].first_child;
while let Some(child) = next_child {
ensure_sufficient_stack(|| self.cache_preorder_invoke(child));
next_child = self.places[child].next_sibling;
}
let end = self.inner_values_buffer.len();
self.inner_values[root] = start..end;
}
}
}#[tracing::instrument(level = "trace", skip(self))]
692 fn cache_preorder_invoke(&mut self, root: PlaceIndex) {
693 debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. });
694 let start = self.inner_values_buffer.len();
695 if let Some(vi) = self.places[root].value_index {
696 self.inner_values_buffer.push(vi);
697 }
698
699 let mut next_child = self.places[root].first_child;
701 while let Some(child) = next_child {
702 ensure_sufficient_stack(|| self.cache_preorder_invoke(child));
703 next_child = self.places[child].next_sibling;
704 }
705
706 let end = self.inner_values_buffer.len();
707 self.inner_values[root] = start..end;
708 }
709}
710
711struct PlaceCollector<'a, 'tcx> {
712 tcx: TyCtxt<'tcx>,
713 body: &'a Body<'tcx>,
714 map: &'a mut Map<'tcx>,
715}
716
717impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
718 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("visit_place",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(718u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["place", "ctxt"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&place)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ctxt)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if !ctxt.is_use() { return; }
self.map.register_place_and_discr(self.tcx, self.body, *place);
}
}
}#[tracing::instrument(level = "trace", skip(self))]
719 fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) {
720 if !ctxt.is_use() {
721 return;
722 }
723
724 self.map.register_place_and_discr(self.tcx, self.body, *place);
725 }
726}
727
728impl<'tcx> Map<'tcx> {
729 pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option<PlaceIndex> {
731 self.projections.get(&(place, elem)).copied()
732 }
733
734 fn find_extra(
736 &self,
737 place: PlaceRef<'_>,
738 extra: impl IntoIterator<Item = TrackElem>,
739 ) -> Option<PlaceIndex> {
740 let mut index = *self.locals[place.local].as_ref()?;
741
742 for &elem in place.projection {
743 index = self.apply(index, elem.try_into().ok()?)?;
744 }
745 for elem in extra {
746 index = self.apply(index, elem)?;
747 }
748
749 Some(index)
750 }
751
752 pub fn find(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
754 self.find_extra(place, [])
755 }
756
757 pub fn find_discr(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
759 self.find_extra(place, [TrackElem::Discriminant])
760 }
761
762 pub fn find_len(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
764 self.find_extra(place, [TrackElem::DerefLen])
765 }
766
767 pub fn value(&self, place: PlaceIndex) -> Option<ValueIndex> {
769 self.places[place].value_index
770 }
771
772 fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> {
774 Children::new(self, parent)
775 }
776
777 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("for_each_aliasing_place",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(784u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["place",
"tail_elem"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&place)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&tail_elem)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if place.is_indirect_first_projection() { return; }
let Some(mut index) = self.locals[place.local] else { return; };
let elems =
place.projection.iter().map(|&elem|
elem.try_into()).chain(tail_elem.map(Ok));
for elem in elems {
if let Some(vi) = self.places[index].value_index { f(vi); }
let Ok(elem) = elem else { return };
let sub = self.apply(index, elem);
if let TrackElem::Variant(..) | TrackElem::Discriminant = elem
{
self.for_each_variant_sibling(index, sub, f);
}
let Some(sub) = sub else { return };
index = sub;
}
self.for_each_value_inside(index, f);
}
}
}#[tracing::instrument(level = "trace", skip(self, f))]
785 pub fn for_each_aliasing_place(
786 &self,
787 place: PlaceRef<'_>,
788 tail_elem: Option<TrackElem>,
789 f: &mut impl FnMut(ValueIndex),
790 ) {
791 if place.is_indirect_first_projection() {
792 return;
794 }
795 let Some(mut index) = self.locals[place.local] else {
796 return;
798 };
799 let elems = place.projection.iter().map(|&elem| elem.try_into()).chain(tail_elem.map(Ok));
800 for elem in elems {
801 if let Some(vi) = self.places[index].value_index {
803 f(vi);
804 }
805
806 let Ok(elem) = elem else { return };
807 let sub = self.apply(index, elem);
808 if let TrackElem::Variant(..) | TrackElem::Discriminant = elem {
809 self.for_each_variant_sibling(index, sub, f);
811 }
812 let Some(sub) = sub else { return };
813 index = sub;
814 }
815 self.for_each_value_inside(index, f);
816 }
817
818 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("for_each_variant_sibling",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(819u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["parent",
"preserved_child"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&parent)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&preserved_child)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
for sibling in self.children(parent) {
let elem = self.places[sibling].proj_elem;
if let Some(TrackElem::Variant(..) | TrackElem::Discriminant)
= elem && Some(sibling) != preserved_child {
self.for_each_value_inside(sibling, f);
}
}
}
}
}#[tracing::instrument(level = "trace", skip(self, f))]
820 fn for_each_variant_sibling(
821 &self,
822 parent: PlaceIndex,
823 preserved_child: Option<PlaceIndex>,
824 f: &mut impl FnMut(ValueIndex),
825 ) {
826 for sibling in self.children(parent) {
827 let elem = self.places[sibling].proj_elem;
828 if let Some(TrackElem::Variant(..) | TrackElem::Discriminant) = elem
831 && Some(sibling) != preserved_child
833 {
834 self.for_each_value_inside(sibling, f);
835 }
836 }
837 }
838
839 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("for_each_value_inside",
"rustc_mir_dataflow::value_analysis",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/value_analysis.rs"),
::tracing_core::__macro_support::Option::Some(840u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::value_analysis"),
::tracing_core::field::FieldSet::new(&["root"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&root)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if let Some(range) = self.inner_values.get(root) {
let values = &self.inner_values_buffer[range.clone()];
for &v in values { f(v) }
} else {
if let Some(root) = self.places[root].value_index { f(root) }
for child in self.children(root) {
self.for_each_value_inside(child, f);
}
}
}
}
}#[tracing::instrument(level = "trace", skip(self, f))]
841 fn for_each_value_inside(&self, root: PlaceIndex, f: &mut impl FnMut(ValueIndex)) {
842 if let Some(range) = self.inner_values.get(root) {
843 let values = &self.inner_values_buffer[range.clone()];
845 for &v in values {
846 f(v)
847 }
848 } else {
849 if let Some(root) = self.places[root].value_index {
850 f(root)
851 }
852
853 for child in self.children(root) {
854 self.for_each_value_inside(child, f);
855 }
856 }
857 }
858
859 pub fn for_each_projection_value<O>(
861 &self,
862 root: PlaceIndex,
863 value: O,
864 project: &mut impl FnMut(TrackElem, &O) -> Option<O>,
865 f: &mut impl FnMut(PlaceIndex, &O),
866 ) {
867 if let Some(value_range) = self.inner_values.get(root)
869 && value_range.is_empty()
870 {
871 return;
872 }
873
874 if self.places[root].value_index.is_some() {
875 f(root, &value)
876 }
877
878 for child in self.children(root) {
879 let elem = self.places[child].proj_elem.unwrap();
880 if let Some(value) = project(elem, &value) {
881 self.for_each_projection_value(child, value, project, f);
882 }
883 }
884 }
885
886 fn for_each_value_pair(
889 &self,
890 target: PlaceIndex,
891 source: PlaceIndex,
892 f: &mut impl FnMut(ValueIndex, ValueIndex),
893 ) {
894 if let Some(target_value) = self.places[target].value_index
898 && let Some(source_value) = self.places[source].value_index
899 {
900 f(target_value, source_value)
901 }
902 for target_child in self.children(target) {
903 let projection = self.places[target_child].proj_elem.unwrap();
905 if let Some(source_child) = self.projections.get(&(source, projection)) {
906 self.for_each_value_pair(target_child, *source_child, f);
907 }
908 }
909 }
910}
911
912#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for PlaceInfo<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f, "PlaceInfo",
"ty", &self.ty, "value_index", &self.value_index, "proj_elem",
&self.proj_elem, "first_child", &self.first_child, "next_sibling",
&&self.next_sibling)
}
}Debug)]
917struct PlaceInfo<'tcx> {
918 ty: Ty<'tcx>,
920
921 value_index: Option<ValueIndex>,
923
924 proj_elem: Option<TrackElem>,
926
927 first_child: Option<PlaceIndex>,
929
930 next_sibling: Option<PlaceIndex>,
932}
933
934impl<'tcx> PlaceInfo<'tcx> {
935 fn new(ty: Ty<'tcx>, proj_elem: Option<TrackElem>) -> Self {
936 Self { ty, next_sibling: None, first_child: None, proj_elem, value_index: None }
937 }
938}
939
940struct Children<'a, 'tcx> {
941 map: &'a Map<'tcx>,
942 next: Option<PlaceIndex>,
943}
944
945impl<'a, 'tcx> Children<'a, 'tcx> {
946 fn new(map: &'a Map<'tcx>, parent: PlaceIndex) -> Self {
947 Self { map, next: map.places[parent].first_child }
948 }
949}
950
951impl Iterator for Children<'_, '_> {
952 type Item = PlaceIndex;
953
954 fn next(&mut self) -> Option<Self::Item> {
955 match self.next {
956 Some(child) => {
957 self.next = self.map.places[child].next_sibling;
958 Some(child)
959 }
960 None => None,
961 }
962 }
963}
964
965#[derive(#[automatically_derived]
impl<V: ::core::fmt::Debug> ::core::fmt::Debug for ValueOrPlace<V> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ValueOrPlace::Value(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Value",
&__self_0),
ValueOrPlace::Place(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Place",
&__self_0),
}
}
}Debug)]
967pub enum ValueOrPlace<V> {
968 Value(V),
969 Place(PlaceIndex),
970}
971
972impl<V: HasTop> ValueOrPlace<V> {
973 pub const TOP: Self = ValueOrPlace::Value(V::TOP);
974}
975
976#[derive(#[automatically_derived]
impl ::core::marker::Copy for TrackElem { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TrackElem {
#[inline]
fn clone(&self) -> TrackElem {
let _: ::core::clone::AssertParamIsClone<FieldIdx>;
let _: ::core::clone::AssertParamIsClone<VariantIdx>;
*self
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for TrackElem {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
TrackElem::Field(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Field",
&__self_0),
TrackElem::Variant(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Variant", &__self_0),
TrackElem::Discriminant =>
::core::fmt::Formatter::write_str(f, "Discriminant"),
TrackElem::DerefLen =>
::core::fmt::Formatter::write_str(f, "DerefLen"),
}
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for TrackElem {
#[inline]
fn eq(&self, other: &TrackElem) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(TrackElem::Field(__self_0), TrackElem::Field(__arg1_0)) =>
__self_0 == __arg1_0,
(TrackElem::Variant(__self_0), TrackElem::Variant(__arg1_0))
=> __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TrackElem {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<FieldIdx>;
let _: ::core::cmp::AssertParamIsEq<VariantIdx>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for TrackElem {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state);
match self {
TrackElem::Field(__self_0) =>
::core::hash::Hash::hash(__self_0, state),
TrackElem::Variant(__self_0) =>
::core::hash::Hash::hash(__self_0, state),
_ => {}
}
}
}Hash)]
980pub enum TrackElem {
981 Field(FieldIdx),
982 Variant(VariantIdx),
983 Discriminant,
984 DerefLen,
986}
987
988impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
989 type Error = ();
990
991 fn try_from(value: ProjectionElem<V, T>) -> Result<Self, Self::Error> {
992 match value {
993 ProjectionElem::Field(field, _) => Ok(TrackElem::Field(field)),
994 ProjectionElem::Downcast(_, idx) => Ok(TrackElem::Variant(idx)),
995 _ => Err(()),
996 }
997 }
998}
999
1000pub fn iter_fields<'tcx>(
1002 ty: Ty<'tcx>,
1003 tcx: TyCtxt<'tcx>,
1004 typing_env: ty::TypingEnv<'tcx>,
1005 mut f: impl FnMut(Option<VariantIdx>, FieldIdx, Ty<'tcx>),
1006) {
1007 match ty.kind() {
1008 ty::Tuple(list) => {
1009 for (field, ty) in list.iter().enumerate() {
1010 f(None, field.into(), ty);
1011 }
1012 }
1013 ty::Adt(def, args) => {
1014 if def.is_union() {
1015 return;
1016 }
1017 for (v_index, v_def) in def.variants().iter_enumerated() {
1018 let variant = if def.is_struct() { None } else { Some(v_index) };
1019 for (f_index, f_def) in v_def.fields.iter().enumerate() {
1020 let field_ty = f_def.ty(tcx, args);
1021 let field_ty =
1022 tcx.try_normalize_erasing_regions(typing_env, field_ty).unwrap_or_else(
1023 |_| tcx.erase_and_anonymize_regions(field_ty.skip_norm_wip()),
1024 );
1025 f(variant, f_index.into(), field_ty);
1026 }
1027 }
1028 }
1029 ty::Closure(_, args) => {
1030 iter_fields(args.as_closure().tupled_upvars_ty(), tcx, typing_env, f);
1031 }
1032 ty::Coroutine(_, args) => {
1033 iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, typing_env, f);
1034 }
1035 ty::CoroutineClosure(_, args) => {
1036 iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, typing_env, f);
1037 }
1038 _ => (),
1039 }
1040}
1041
1042pub fn excluded_locals(body: &Body<'_>) -> DenseBitSet<Local> {
1044 struct Collector {
1045 result: DenseBitSet<Local>,
1046 }
1047
1048 impl<'tcx> Visitor<'tcx> for Collector {
1049 fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
1050 if context.may_observe_address() && !place.is_indirect() {
1051 self.result.insert(place.local);
1054 }
1055 }
1056 }
1057
1058 let mut collector = Collector { result: DenseBitSet::new_empty(body.local_decls.len()) };
1059 collector.visit_body(body);
1060 collector.result
1061}
1062
1063fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
1064 place: PlaceIndex,
1065 place_str: &str,
1066 new: &StateData<V>,
1067 old: Option<&StateData<V>>,
1068 map: &Map<'_>,
1069 f: &mut Formatter<'_>,
1070) -> std::fmt::Result {
1071 if let Some(value) = map.places[place].value_index {
1072 match old {
1073 None => f.write_fmt(format_args!("{0}: {1:?}\n", place_str, new.get(value)))writeln!(f, "{}: {:?}", place_str, new.get(value))?,
1074 Some(old) => {
1075 if new.get(value) != old.get(value) {
1076 f.write_fmt(format_args!("\u{1f}-{0}: {1:?}\n", place_str, old.get(value)))writeln!(f, "\u{001f}-{}: {:?}", place_str, old.get(value))?;
1077 f.write_fmt(format_args!("\u{1f}+{0}: {1:?}\n", place_str, new.get(value)))writeln!(f, "\u{001f}+{}: {:?}", place_str, new.get(value))?;
1078 }
1079 }
1080 }
1081 }
1082
1083 for child in map.children(place) {
1084 let info_elem = map.places[child].proj_elem.unwrap();
1085 let child_place_str = match info_elem {
1086 TrackElem::Discriminant => {
1087 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("discriminant({0})", place_str))
})format!("discriminant({place_str})")
1088 }
1089 TrackElem::Variant(idx) => {
1090 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("({0} as {1:?})", place_str, idx))
})format!("({place_str} as {idx:?})")
1091 }
1092 TrackElem::Field(field) => {
1093 if place_str.starts_with('*') {
1094 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("({0}).{1}", place_str,
field.index()))
})format!("({}).{}", place_str, field.index())
1095 } else {
1096 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.{1}", place_str,
field.index()))
})format!("{}.{}", place_str, field.index())
1097 }
1098 }
1099 TrackElem::DerefLen => {
1100 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Len(*{0})", place_str))
})format!("Len(*{})", place_str)
1101 }
1102 };
1103 debug_with_context_rec(child, &child_place_str, new, old, map, f)?;
1104 }
1105
1106 Ok(())
1107}
1108
1109pub fn debug_with_context<V: Debug + Eq + HasBottom>(
1110 new: &StateData<V>,
1111 old: Option<&StateData<V>>,
1112 map: &Map<'_>,
1113 f: &mut Formatter<'_>,
1114) -> std::fmt::Result {
1115 for (local, place) in map.locals.iter_enumerated() {
1116 if let Some(place) = place {
1117 debug_with_context_rec(*place, &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", local))
})format!("{local:?}"), new, old, map, f)?;
1118 }
1119 }
1120 Ok(())
1121}