Skip to main content

rustc_mir_dataflow/
value_analysis.rs

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    /// This index uniquely identifies a place.
20    ///
21    /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` corresponds to a tracked
22    /// place. However, every tracked place and all places along its projection have a `PlaceIndex`.
23    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    /// This index uniquely identifies a tracked place and therefore a slot in [`State`].
28    pub struct ValueIndex {}
29);
30
31/// See [`State`].
32#[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    /// This map only contains values that are not `⊥`.
36    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/// Dataflow state.
85///
86/// Every instance specifies a lattice that represents the possible values of a single tracked
87/// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an
88/// element of `{unreachable} ∪ (P -> V)`. This again forms a lattice, where the bottom element is
89/// `unreachable` and the top element is the mapping `p ↦ ⊤`. Note that the mapping `p ↦ ⊥` is not
90/// the bottom element (because joining an unreachable and any other reachable state yields a
91/// reachable state). All operations on unreachable states are ignored.
92///
93/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
94#[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    /// Assign `value` to all places that are contained in `place` or may alias one.
128    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    /// Assign `TOP` to all places that are contained in `place` or may alias one.
133    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    /// Assign `value` to the discriminant of `place` and all places that may alias it.
141    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    /// Assign `TOP` to the discriminant of `place` and all places that may alias it.
146    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    /// This method is the most general version of the `flood_*` method.
154    ///
155    /// Assign `value` on the given place and all places that may alias it. In particular, when
156    /// the given place has a variant downcast, we invoke the function on all the other variants.
157    ///
158    /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
159    /// as such.
160    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    /// Low-level method that assigns to a place.
172    /// This does nothing if the place is not tracked.
173    ///
174    /// The target place must have been flooded before calling this method.
175    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    /// Low-level method that assigns a value to a place.
183    /// This does nothing if the place is not tracked.
184    ///
185    /// The target place must have been flooded before calling this method.
186    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    /// Copies `source` to `target`, including all tracked places beneath.
194    ///
195    /// If `target` contains a place that is not contained in `source`, it will be overwritten with
196    /// Top. Also, because this will copy all entries one after another, it may only be used for
197    /// places that are non-overlapping or identical.
198    ///
199    /// The target place must have been flooded before calling this method.
200    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    /// Helper method to interpret `target = result`.
208    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    /// Helper method for assignments to a discriminant.
219    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    /// Retrieve the value stored for a place, or `None` if it is not tracked.
230    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    /// Retrieve the discriminant stored for a place, or `None` if it is not tracked.
236    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    /// Retrieve the value stored for a place index, or `None` if it is not tracked.
242    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    /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
252    ///
253    /// This method returns ⊥ if the place is tracked and the state is unreachable.
254    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            // Because this is unreachable, we can return any value we want.
261            State::Unreachable => V::BOTTOM,
262        }
263    }
264
265    /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
266    ///
267    /// This method returns ⊥ the current state is unreachable.
268    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            // Because this is unreachable, we can return any value we want.
275            State::Unreachable => V::BOTTOM,
276        }
277    }
278
279    /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
280    ///
281    /// This method returns ⊥ the current state is unreachable.
282    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                // Because this is unreachable, we can return any value we want.
292                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/// Partial mapping from [`Place`] to [`PlaceIndex`], where some places also have a [`ValueIndex`].
312///
313/// This data structure essentially maintains a tree of places and their projections. Some
314/// additional bookkeeping is done, to speed up traversal over this tree:
315/// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children.
316/// - To directly get the child for a specific projection, there is a `projections` map.
317#[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    // The Range corresponds to a slice into `inner_values_buffer`.
325    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    /// Returns a map that only tracks places whose type has scalar layout.
337    ///
338    /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
339    /// chosen is an implementation detail and may not be relied upon (other than that their type
340    /// are scalars).
341    #[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    /// Register all non-excluded places that have scalar layout.
369    #[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        // Start by constructing the places for each bare local.
374        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            // Create a place for the local.
383            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    /// Collect syntactic places from body, and create `PlaceIndex` for them.
390    #[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    /// Just collecting syntactic places is not enough. We may need to propagate this pattern:
397    ///      _1 = (const 5u32, const 13i64);
398    ///      _2 = _1;
399    ///      _3 = (_2.0 as u32);
400    ///
401    /// `_1.0` does not appear, but we still need to track it. This is achieved by propagating
402    /// projections from assignments. We recorded an assignment between `_2` and `_1`, so we
403    /// want `_1` and `_2` to have the same sub-places.
404    #[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        // Collect syntactic places and assignments between them.
407        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                            // Do not propagate unions.
429                            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        // This is a fixpoint loop does. While we are still creating places, run through
466        // all the assignments, and register places for children.
467        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                // Mirror children from `lhs` in `rhs`.
475                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                // Conversely, mirror children from `rhs` in `lhs`.
488                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    /// Create values for places whose type have scalar layout.
504    #[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            // The user requires a bound on the number of created values.
510            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            // Allocate a value slot if it doesn't have one, and the user requested one.
523            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        // Pre-compute the tree of ValueIndex nested in each PlaceIndex.
533        // `inner_values_buffer[inner_values[place]]` is the set of all the values
534        // reachable by projecting `place`.
535        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    /// Trim useless places.
545    #[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        // Create a place for this projection.
583        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        // Allocate a value slot if it doesn't have one, and the user requested one.
647        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        // Tree to copy.
661        source: PlaceIndex,
662        // Tree to build.
663        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        // Iterate over `source` children and recurse.
676        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            // Try to find corresponding child and recurse. Reasoning is similar as above.
681            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    /// Precompute the list of values inside `root` and store it inside
690    /// as a slice within `inner_values_buffer`.
691    #[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        // We manually iterate instead of using `children` as we need to mutate `self`.
700        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    /// Applies a single projection element, yielding the corresponding child.
730    pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option<PlaceIndex> {
731        self.projections.get(&(place, elem)).copied()
732    }
733
734    /// Locates the given place, if it exists in the tree.
735    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    /// Locates the given place, if it exists in the tree.
753    pub fn find(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
754        self.find_extra(place, [])
755    }
756
757    /// Locates the given place and applies `Discriminant`, if it exists in the tree.
758    pub fn find_discr(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
759        self.find_extra(place, [TrackElem::Discriminant])
760    }
761
762    /// Locates the given place and applies `DerefLen`, if it exists in the tree.
763    pub fn find_len(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> {
764        self.find_extra(place, [TrackElem::DerefLen])
765    }
766
767    /// Locates the value corresponding to the given place.
768    pub fn value(&self, place: PlaceIndex) -> Option<ValueIndex> {
769        self.places[place].value_index
770    }
771
772    /// Iterate over all direct children.
773    fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> {
774        Children::new(self, parent)
775    }
776
777    /// Invoke a function on the given place and all places that may alias it.
778    ///
779    /// In particular, when the given place has a variant downcast, we invoke the function on all
780    /// the other variants.
781    ///
782    /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
783    /// as such.
784    #[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            // We do not track indirect places.
793            return;
794        }
795        let Some(mut index) = self.locals[place.local] else {
796            // The local is not tracked at all, so it does not alias anything.
797            return;
798        };
799        let elems = place.projection.iter().map(|&elem| elem.try_into()).chain(tail_elem.map(Ok));
800        for elem in elems {
801            // A field aliases the parent place.
802            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                // Enum variant fields and enum discriminants alias each another.
810                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    /// Invoke the given function on all the descendants of the given place, except one branch.
819    #[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            // Only invalidate variants and discriminant. Fields (for coroutines) are not
829            // invalidated by assignment to a variant.
830            if let Some(TrackElem::Variant(..) | TrackElem::Discriminant) = elem
831                // Only invalidate the other variants, the current one is fine.
832                && Some(sibling) != preserved_child
833            {
834                self.for_each_value_inside(sibling, f);
835            }
836        }
837    }
838
839    /// Invoke a function on each value in the given place and all descendants.
840    #[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            // Optimized path: we have cached the inner values.
844            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    /// Invoke a function on each value in the given place and all descendants.
860    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        // Fast path is there is nothing to do.
868        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    /// Recursively iterates on each value contained in `target`, paired with matching projection
887    /// inside `source`.
888    fn for_each_value_pair(
889        &self,
890        target: PlaceIndex,
891        source: PlaceIndex,
892        f: &mut impl FnMut(ValueIndex, ValueIndex),
893    ) {
894        // If both places are tracked, we copy the value to the target.
895        // If the target is tracked, but the source is not, we do nothing, as invalidation has
896        // already been performed.
897        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            // Try to find corresponding child and recurse. Reasoning is similar as above.
904            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/// This is the information tracked for every [`PlaceIndex`] and is stored by [`Map`].
913///
914/// Together, `first_child` and `next_sibling` form an intrusive linked list, which is used to
915/// model a tree structure (a replacement for a member like `children: Vec<PlaceIndex>`).
916#[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    /// Type of the referenced place.
919    ty: Ty<'tcx>,
920
921    /// We store a [`ValueIndex`] if and only if the placed is tracked by the analysis.
922    value_index: Option<ValueIndex>,
923
924    /// The projection used to go from parent to this node (only None for root).
925    proj_elem: Option<TrackElem>,
926
927    /// The leftmost child.
928    first_child: Option<PlaceIndex>,
929
930    /// Index of the sibling to the right of this node.
931    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/// Used as the result of an operand or r-value.
966#[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/// The set of projection elements that can be used by a tracked place.
977///
978/// Although only field projections are currently allowed, this could change in the future.
979#[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    // Length of a slice.
985    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
1000/// Invokes `f` on all direct fields of `ty`.
1001pub 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
1042/// Returns all locals with projections that have their reference or address taken.
1043pub 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                // A pointer to a place could be used to access other places with the same local,
1052                // hence we have to exclude the local completely.
1053                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}