Skip to main content

rustc_mir_dataflow/impls/
initialized.rs

1use std::assert_matches;
2
3use rustc_abi::VariantIdx;
4use rustc_index::Idx;
5use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
6use rustc_middle::bug;
7use rustc_middle::mir::{
8    self, Body, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
9};
10use rustc_middle::ty::util::Discr;
11use rustc_middle::ty::{self, TyCtxt};
12use smallvec::SmallVec;
13use tracing::{debug, instrument};
14
15use crate::drop_flag_effects::{DropFlagState, InactiveVariants};
16use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
17use crate::{
18    Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
19    drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
20};
21
22// Used by both `MaybeInitializedPlaces` and `MaybeUninitializedPlaces`.
23pub struct MaybePlacesSwitchIntData<'tcx> {
24    enum_place: mir::Place<'tcx>,
25    discriminants: Vec<(VariantIdx, Discr<'tcx>)>,
26    index: usize,
27}
28
29impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
30    /// Creates a `SmallVec` mapping each target in `targets` to its `VariantIdx`.
31    fn variants(&mut self, targets: &mir::SwitchTargets) -> SmallVec<[VariantIdx; 4]> {
32        self.index = 0;
33        targets.all_values().iter().map(|value| self.next_discr(value.get())).collect()
34    }
35
36    // The discriminant order in the `SwitchInt` targets should match the order yielded by
37    // `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
38    // corresponding variant in linear time.
39    fn next_discr(&mut self, value: u128) -> VariantIdx {
40        // An out-of-bounds abort will occur if the discriminant ordering isn't as described above.
41        loop {
42            let (variant, discr) = self.discriminants[self.index];
43            self.index += 1;
44            if discr.val == value {
45                return variant;
46            }
47        }
48    }
49}
50
51impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
52    fn new(
53        tcx: TyCtxt<'tcx>,
54        body: &Body<'tcx>,
55        block: mir::BasicBlock,
56        discr: &mir::Operand<'tcx>,
57    ) -> Option<Self> {
58        let Some(discr) = discr.place() else { return None };
59
60        // Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt`
61        // is an enum discriminant.
62        //
63        // We expect such blocks to have a call to `discriminant` as their last statement like so:
64        // ```text
65        // ...
66        // _42 = discriminant(_1)
67        // SwitchInt(_42, ..)
68        // ```
69        // If the basic block matches this pattern, this function gathers the place corresponding
70        // to the enum (`_1` in the example above) as well as the discriminants.
71        let block_data = &body[block];
72        for statement in block_data.statements.iter().rev() {
73            match statement.kind {
74                mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(enum_place)))
75                    if lhs == discr =>
76                {
77                    match enum_place.ty(body, tcx).ty.kind() {
78                        ty::Adt(enum_def, _) => {
79                            return Some(MaybePlacesSwitchIntData {
80                                enum_place,
81                                discriminants: enum_def.discriminants(tcx).collect(),
82                                index: 0,
83                            });
84                        }
85
86                        // `Rvalue::Discriminant` is also used to get the active yield point for a
87                        // coroutine, but we do not need edge-specific effects in that case. This
88                        // may change in the future.
89                        ty::Coroutine(..) => break,
90
91                        t => ::rustc_middle::util::bug::bug_fmt(format_args!("`discriminant` called on unexpected type {0:?}",
        t))bug!("`discriminant` called on unexpected type {:?}", t),
92                    }
93                }
94                mir::StatementKind::Coverage(_) => continue,
95                _ => break,
96            }
97        }
98        None
99    }
100}
101
102/// `MaybeInitializedPlaces` tracks all places that might be
103/// initialized upon reaching a particular point in the control flow
104/// for a function.
105///
106/// For example, in code like the following, we have corresponding
107/// dataflow information shown in the right-hand comments.
108///
109/// ```rust
110/// struct S;
111/// #[rustfmt::skip]
112/// fn foo(p: bool) {                           // maybe-init:
113///                                             // {p}
114///     let a = S; let mut b = S; let c; let d; // {p, a, b}
115///
116///     if p {
117///         drop(a);                            // {p,    b}
118///         b = S;                              // {p,    b}
119///
120///     } else {
121///         drop(b);                            // {p, a}
122///         d = S;                              // {p, a,       d}
123///
124///     }                                       // {p, a, b,    d}
125///
126///     c = S;                                  // {p, a, b, c, d}
127/// }
128/// ```
129///
130/// To determine whether a place is *definitely* initialized at a
131/// particular control-flow point, one can take the set-complement
132/// of the data from `MaybeUninitializedPlaces` at the corresponding
133/// control-flow point.
134///
135/// Similarly, at a given `drop` statement, the set-intersection
136/// between this data and `MaybeUninitializedPlaces` yields the set of
137/// places that would require a dynamic drop-flag at that statement.
138pub struct MaybeInitializedPlaces<'a, 'tcx> {
139    tcx: TyCtxt<'tcx>,
140    body: &'a Body<'tcx>,
141    move_data: &'a MoveData<'tcx>,
142    exclude_inactive_in_otherwise: bool,
143    skip_unreachable_unwind: bool,
144}
145
146impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
147    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
148        MaybeInitializedPlaces {
149            tcx,
150            body,
151            move_data,
152            exclude_inactive_in_otherwise: false,
153            skip_unreachable_unwind: false,
154        }
155    }
156
157    /// Ensures definitely inactive variants are excluded from the set of initialized places for
158    /// blocks reached through an `otherwise` edge.
159    pub fn exclude_inactive_in_otherwise(mut self) -> Self {
160        self.exclude_inactive_in_otherwise = true;
161        self
162    }
163
164    pub fn skipping_unreachable_unwind(mut self) -> Self {
165        self.skip_unreachable_unwind = true;
166        self
167    }
168
169    pub fn is_unwind_dead(
170        &self,
171        place: mir::Place<'tcx>,
172        state: &<Self as Analysis<'tcx>>::Domain,
173    ) -> bool {
174        if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
175            let mut maybe_live = false;
176            on_all_children_bits(self.move_data(), path, |child| {
177                maybe_live |= state.contains(child);
178            });
179            !maybe_live
180        } else {
181            false
182        }
183    }
184}
185
186impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
187    fn move_data(&self) -> &MoveData<'tcx> {
188        self.move_data
189    }
190}
191
192/// `MaybeUninitializedPlaces` tracks all places that might be
193/// uninitialized upon reaching a particular point in the control flow
194/// for a function.
195///
196/// For example, in code like the following, we have corresponding
197/// dataflow information shown in the right-hand comments.
198///
199/// ```rust
200/// struct S;
201/// #[rustfmt::skip]
202/// fn foo(p: bool) {                           // maybe-uninit:
203///                                             // {a, b, c, d}
204///     let a = S; let mut b = S; let c; let d; // {      c, d}
205///
206///     if p {
207///         drop(a);                            // {a,    c, d}
208///         b = S;                              // {a,    c, d}
209///
210///     } else {
211///         drop(b);                            // {   b, c, d}
212///         d = S;                              // {   b, c   }
213///
214///     }                                       // {a, b, c, d}
215///
216///     c = S;                                  // {a, b,    d}
217/// }
218/// ```
219///
220/// To determine whether a place is *definitely* uninitialized at a
221/// particular control-flow point, one can take the set-complement
222/// of the data from `MaybeInitializedPlaces` at the corresponding
223/// control-flow point.
224///
225/// Similarly, at a given `drop` statement, the set-intersection
226/// between this data and `MaybeInitializedPlaces` yields the set of
227/// places that would require a dynamic drop-flag at that statement.
228pub struct MaybeUninitializedPlaces<'a, 'tcx> {
229    tcx: TyCtxt<'tcx>,
230    body: &'a Body<'tcx>,
231    move_data: &'a MoveData<'tcx>,
232
233    mark_inactive_variants_as_uninit: bool,
234    include_inactive_in_otherwise: bool,
235    skip_unreachable_unwind: DenseBitSet<mir::BasicBlock>,
236}
237
238impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
239    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
240        MaybeUninitializedPlaces {
241            tcx,
242            body,
243            move_data,
244            mark_inactive_variants_as_uninit: false,
245            include_inactive_in_otherwise: false,
246            skip_unreachable_unwind: DenseBitSet::new_empty(body.basic_blocks.len()),
247        }
248    }
249
250    /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
251    /// enum discriminant.
252    ///
253    /// This is correct in a vacuum but is not the default because it causes problems in the borrow
254    /// checker, where this information gets propagated along `FakeEdge`s.
255    pub fn mark_inactive_variants_as_uninit(mut self) -> Self {
256        self.mark_inactive_variants_as_uninit = true;
257        self
258    }
259
260    /// Ensures definitely inactive variants are included in the set of uninitialized places for
261    /// blocks reached through an `otherwise` edge.
262    pub fn include_inactive_in_otherwise(mut self) -> Self {
263        self.include_inactive_in_otherwise = true;
264        self
265    }
266
267    pub fn skipping_unreachable_unwind(
268        mut self,
269        unreachable_unwind: DenseBitSet<mir::BasicBlock>,
270    ) -> Self {
271        self.skip_unreachable_unwind = unreachable_unwind;
272        self
273    }
274}
275
276impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
277    fn move_data(&self) -> &MoveData<'tcx> {
278        self.move_data
279    }
280}
281
282/// `EverInitializedPlaces` tracks all initializations that may have occurred
283/// upon reaching a particular point in the control flow for a function,
284/// without an intervening `StorageDead`.
285///
286/// This dataflow is used to determine if an immutable local variable may
287/// be assigned to.
288///
289/// For example, in code like the following, we have corresponding
290/// dataflow information shown in the right-hand comments. Underscored indices
291/// are used to distinguish between multiple initializations of the same local
292/// variable, e.g. `b_0` and `b_1`.
293///
294/// ```rust
295/// struct S;
296/// #[rustfmt::skip]
297/// fn foo(p: bool) {                           // ever-init:
298///                                             // {p,                  }
299///     let a = S; let mut b = S; let c; let d; // {p, a, b_0,          }
300///
301///     if p {
302///         drop(a);                            // {p, a, b_0,          }
303///         b = S;                              // {p, a, b_0, b_1,     }
304///
305///     } else {
306///         drop(b);                            // {p, a, b_0, b_1,     }
307///         d = S;                              // {p, a, b_0, b_1,    d}
308///
309///     }                                       // {p, a, b_0, b_1,    d}
310///
311///     c = S;                                  // {p, a, b_0, b_1, c, d}
312/// }
313/// ```
314pub struct EverInitializedPlaces<'a, 'tcx> {
315    body: &'a Body<'tcx>,
316    move_data: &'a MoveData<'tcx>,
317}
318
319impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> {
320    pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
321        EverInitializedPlaces { body, move_data }
322    }
323}
324
325impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
326    fn move_data(&self) -> &MoveData<'tcx> {
327        self.move_data
328    }
329}
330
331impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
332    fn update_bits(
333        state: &mut <Self as Analysis<'tcx>>::Domain,
334        path: MovePathIndex,
335        dfstate: DropFlagState,
336    ) {
337        match dfstate {
338            DropFlagState::Absent => state.kill(path),
339            DropFlagState::Present => state.gen_(path),
340        }
341    }
342}
343
344impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
345    fn update_bits(
346        state: &mut <Self as Analysis<'tcx>>::Domain,
347        path: MovePathIndex,
348        dfstate: DropFlagState,
349    ) {
350        match dfstate {
351            DropFlagState::Absent => state.gen_(path),
352            DropFlagState::Present => state.kill(path),
353        }
354    }
355}
356
357impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
358    /// There can be many more `MovePathIndex` than there are locals in a MIR body.
359    /// We use a mixed bitset to avoid paying too high a memory footprint.
360    type Domain = MaybeReachable<MixedBitSet<MovePathIndex>>;
361
362    type SwitchIntData = MaybePlacesSwitchIntData<'tcx>;
363
364    const NAME: &'static str = "maybe_init";
365
366    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
367        // bottom = uninitialized
368        MaybeReachable::Unreachable
369    }
370
371    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
372        *state =
373            MaybeReachable::Reachable(MixedBitSet::new_empty(self.move_data().move_paths.len()));
374        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
375            if !(s == DropFlagState::Present) {
    ::core::panicking::panic("assertion failed: s == DropFlagState::Present")
};assert!(s == DropFlagState::Present);
376            state.gen_(path);
377        });
378    }
379
380    fn apply_primary_statement_effect(
381        &self,
382        state: &mut Self::Domain,
383        statement: &mir::Statement<'tcx>,
384        location: Location,
385    ) {
386        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
387            Self::update_bits(state, path, s)
388        });
389
390        // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
391        if self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration
392            && let Some((_, rvalue)) = statement.kind.as_assign()
393            && let mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
394                // FIXME: Does `&raw const foo` allow mutation? See #90413.
395                | mir::Rvalue::RawPtr(_, place) = rvalue
396            && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
397        {
398            on_all_children_bits(self.move_data(), mpi, |child| {
399                state.gen_(child);
400            })
401        }
402    }
403
404    fn apply_primary_terminator_effect<'mir>(
405        &self,
406        state: &mut Self::Domain,
407        terminator: &'mir mir::Terminator<'tcx>,
408        location: Location,
409    ) -> TerminatorEdges<'mir, 'tcx> {
410        // Note: `edges` must be computed first because `drop_flag_effects_for_location` can change
411        // the result of `is_unwind_dead`.
412        let mut edges = terminator.edges();
413        if self.skip_unreachable_unwind
414            && let mir::TerminatorKind::Drop {
415                target,
416                unwind,
417                place,
418                replace: _,
419                drop: _,
420                async_fut: _,
421            } = terminator.kind
422            && #[allow(non_exhaustive_omitted_patterns)] match unwind {
    mir::UnwindAction::Cleanup(_) => true,
    _ => false,
}matches!(unwind, mir::UnwindAction::Cleanup(_))
423            && self.is_unwind_dead(place, state)
424        {
425            edges = TerminatorEdges::Single(target);
426        }
427        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
428            Self::update_bits(state, path, s)
429        });
430        edges
431    }
432
433    fn apply_call_return_effect(
434        &self,
435        state: &mut Self::Domain,
436        _block: mir::BasicBlock,
437        return_places: CallReturnPlaces<'_, 'tcx>,
438    ) {
439        return_places.for_each(|place| {
440            // when a call returns successfully, that means we need to set
441            // the bits for that dest_place to 1 (initialized).
442            on_lookup_result_bits(
443                self.move_data(),
444                self.move_data().rev_lookup.find(place.as_ref()),
445                |mpi| {
446                    state.gen_(mpi);
447                },
448            );
449        });
450    }
451
452    fn get_switch_int_data(
453        &self,
454        block: mir::BasicBlock,
455        discr: &mir::Operand<'tcx>,
456    ) -> Option<Self::SwitchIntData> {
457        if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration {
458            return None;
459        }
460
461        MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
462    }
463
464    fn apply_switch_int_edge_effect(
465        &self,
466        data: &mut Self::SwitchIntData,
467        state: &mut Self::Domain,
468        value: SwitchTargetValue,
469        targets: &mir::SwitchTargets,
470    ) {
471        let inactive_variants = match value {
472            SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
473            SwitchTargetValue::Otherwise if self.exclude_inactive_in_otherwise => {
474                InactiveVariants::Inactives(data.variants(targets))
475            }
476            _ => return,
477        };
478
479        // Kill all move paths that correspond to variants we know to be inactive along this
480        // particular outgoing edge of a `SwitchInt`.
481        drop_flag_effects::on_all_inactive_variants(
482            self.move_data,
483            data.enum_place,
484            &inactive_variants,
485            |mpi| state.kill(mpi),
486        );
487    }
488}
489
490/// There can be many more `MovePathIndex` than there are locals in a MIR body.
491/// We use a mixed bitset to avoid paying too high a memory footprint.
492pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
493
494impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
495    type Domain = MaybeUninitializedPlacesDomain;
496
497    type SwitchIntData = MaybePlacesSwitchIntData<'tcx>;
498
499    const NAME: &'static str = "maybe_uninit";
500
501    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
502        // bottom = initialized (`initialize_start_block` overwrites this on first entry)
503        MixedBitSet::new_empty(self.move_data().move_paths.len())
504    }
505
506    // sets state bits for Arg places
507    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
508        // set all bits to 1 (uninit) before gathering counter-evidence
509        state.insert_all();
510
511        drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
512            if !(s == DropFlagState::Present) {
    ::core::panicking::panic("assertion failed: s == DropFlagState::Present")
};assert!(s == DropFlagState::Present);
513            state.remove(path);
514        });
515    }
516
517    fn apply_primary_statement_effect(
518        &self,
519        state: &mut Self::Domain,
520        _statement: &mir::Statement<'tcx>,
521        location: Location,
522    ) {
523        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
524            Self::update_bits(state, path, s)
525        });
526
527        // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
528        // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
529    }
530
531    fn apply_primary_terminator_effect<'mir>(
532        &self,
533        state: &mut Self::Domain,
534        terminator: &'mir mir::Terminator<'tcx>,
535        location: Location,
536    ) -> TerminatorEdges<'mir, 'tcx> {
537        drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
538            Self::update_bits(state, path, s)
539        });
540        if self.skip_unreachable_unwind.contains(location.block) {
541            let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!() };
542            match unwind {
    mir::UnwindAction::Cleanup(_) => {}
    ref left_val => {
        ::core::panicking::assert_matches_failed(left_val,
            "mir::UnwindAction::Cleanup(_)", ::core::option::Option::None);
    }
};assert_matches!(unwind, mir::UnwindAction::Cleanup(_));
543            TerminatorEdges::Single(target)
544        } else {
545            terminator.edges()
546        }
547    }
548
549    fn apply_call_return_effect(
550        &self,
551        state: &mut Self::Domain,
552        _block: mir::BasicBlock,
553        return_places: CallReturnPlaces<'_, 'tcx>,
554    ) {
555        return_places.for_each(|place| {
556            // when a call returns successfully, that means we need to set
557            // the bits for that dest_place to 0 (initialized).
558            on_lookup_result_bits(
559                self.move_data(),
560                self.move_data().rev_lookup.find(place.as_ref()),
561                |mpi| {
562                    state.kill(mpi);
563                },
564            );
565        });
566    }
567
568    fn get_switch_int_data(
569        &self,
570        block: mir::BasicBlock,
571        discr: &mir::Operand<'tcx>,
572    ) -> Option<Self::SwitchIntData> {
573        if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration {
574            return None;
575        }
576
577        if !self.mark_inactive_variants_as_uninit {
578            return None;
579        }
580
581        MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
582    }
583
584    fn apply_switch_int_edge_effect(
585        &self,
586        data: &mut Self::SwitchIntData,
587        state: &mut Self::Domain,
588        value: SwitchTargetValue,
589        targets: &mir::SwitchTargets,
590    ) {
591        let inactive_variants = match value {
592            SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
593            SwitchTargetValue::Otherwise if self.include_inactive_in_otherwise => {
594                InactiveVariants::Inactives(data.variants(targets))
595            }
596            _ => return,
597        };
598
599        // Mark all move paths that correspond to variants other than this one as maybe
600        // uninitialized (in reality, they are *definitely* uninitialized).
601        drop_flag_effects::on_all_inactive_variants(
602            self.move_data,
603            data.enum_place,
604            &inactive_variants,
605            |mpi| state.gen_(mpi),
606        );
607    }
608}
609
610/// There can be many more `InitIndex` than there are locals in a MIR body.
611/// We use a mixed bitset to avoid paying too high a memory footprint.
612pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
613
614impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
615    type Domain = EverInitializedPlacesDomain;
616
617    const NAME: &'static str = "ever_init";
618
619    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
620        // bottom = no initialized variables by default
621        MixedBitSet::new_empty(self.move_data().inits.len())
622    }
623
624    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
625        for arg_init in 0..body.arg_count {
626            state.insert(InitIndex::new(arg_init));
627        }
628    }
629
630    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("apply_primary_statement_effect",
                                    "rustc_mir_dataflow::impls::initialized",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                    ::tracing_core::__macro_support::Option::Some(630u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                    ::tracing_core::field::FieldSet::new(&["stmt", "location"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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(&stmt)
                                                            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(&location)
                                                            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;
        }
        {
            let move_data = self.move_data();
            let init_path_map = &move_data.init_path_map;
            let init_loc_map = &move_data.init_loc_map;
            let rev_lookup = &move_data.rev_lookup;
            {
                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/impls/initialized.rs:642",
                                    "rustc_mir_dataflow::impls::initialized",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                    ::tracing_core::__macro_support::Option::Some(642u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                    ::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!("initializes move_indexes {0:?}",
                                                                init_loc_map[location]) as &dyn Value))])
                        });
                } else { ; }
            };
            state.gen_all(init_loc_map[location].iter().copied());
            if let mir::StatementKind::StorageDead(local) = stmt.kind &&
                    let Some(move_path_index) = rev_lookup.find_local(local) {
                {
                    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/impls/initialized.rs:650",
                                        "rustc_mir_dataflow::impls::initialized",
                                        ::tracing::Level::DEBUG,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                        ::tracing_core::__macro_support::Option::Some(650u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                        ::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!("clears the ever initialized status of {0:?}",
                                                                    init_path_map[move_path_index]) as &dyn Value))])
                            });
                    } else { ; }
                };
                state.kill_all(init_path_map[move_path_index].iter().copied());
            }
        }
    }
}#[instrument(skip(self, state), level = "debug")]
631    fn apply_primary_statement_effect(
632        &self,
633        state: &mut Self::Domain,
634        stmt: &mir::Statement<'tcx>,
635        location: Location,
636    ) {
637        let move_data = self.move_data();
638        let init_path_map = &move_data.init_path_map;
639        let init_loc_map = &move_data.init_loc_map;
640        let rev_lookup = &move_data.rev_lookup;
641
642        debug!("initializes move_indexes {:?}", init_loc_map[location]);
643        state.gen_all(init_loc_map[location].iter().copied());
644
645        if let mir::StatementKind::StorageDead(local) = stmt.kind
646            // End inits for StorageDead, so that an immutable variable can
647            // be reinitialized on the next iteration of the loop.
648            && let Some(move_path_index) = rev_lookup.find_local(local)
649        {
650            debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]);
651            state.kill_all(init_path_map[move_path_index].iter().copied());
652        }
653    }
654
655    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("apply_primary_terminator_effect",
                                    "rustc_mir_dataflow::impls::initialized",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                    ::tracing_core::__macro_support::Option::Some(655u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                    ::tracing_core::field::FieldSet::new(&["location"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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(&location)
                                                            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: TerminatorEdges<'mir, 'tcx> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let (body, move_data) = (self.body, self.move_data());
            let term = body[location.block].terminator();
            let init_loc_map = &move_data.init_loc_map;
            {
                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/impls/initialized.rs:665",
                                    "rustc_mir_dataflow::impls::initialized",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                    ::tracing_core::__macro_support::Option::Some(665u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                    ::tracing_core::field::FieldSet::new(&["term"],
                                        ::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(&debug(&term) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            {
                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/impls/initialized.rs:666",
                                    "rustc_mir_dataflow::impls::initialized",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_dataflow/src/impls/initialized.rs"),
                                    ::tracing_core::__macro_support::Option::Some(666u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_dataflow::impls::initialized"),
                                    ::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!("initializes move_indexes {0:?}",
                                                                init_loc_map[location]) as &dyn Value))])
                        });
                } else { ; }
            };
            state.gen_all(init_loc_map[location].iter().filter(|init_index|
                            {
                                move_data.inits[**init_index].kind !=
                                    InitKind::NonPanicPathOnly
                            }).copied());
            terminator.edges()
        }
    }
}#[instrument(skip(self, state, terminator), level = "debug")]
656    fn apply_primary_terminator_effect<'mir>(
657        &self,
658        state: &mut Self::Domain,
659        terminator: &'mir mir::Terminator<'tcx>,
660        location: Location,
661    ) -> TerminatorEdges<'mir, 'tcx> {
662        let (body, move_data) = (self.body, self.move_data());
663        let term = body[location.block].terminator();
664        let init_loc_map = &move_data.init_loc_map;
665        debug!(?term);
666        debug!("initializes move_indexes {:?}", init_loc_map[location]);
667        state.gen_all(
668            init_loc_map[location]
669                .iter()
670                .filter(|init_index| {
671                    move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly
672                })
673                .copied(),
674        );
675        terminator.edges()
676    }
677
678    fn apply_call_return_effect(
679        &self,
680        state: &mut Self::Domain,
681        block: mir::BasicBlock,
682        _return_places: CallReturnPlaces<'_, 'tcx>,
683    ) {
684        let move_data = self.move_data();
685        let init_loc_map = &move_data.init_loc_map;
686
687        let call_loc = self.body.terminator_loc(block);
688        for init_index in &init_loc_map[call_loc] {
689            state.gen_(*init_index);
690        }
691    }
692}