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