Skip to main content

rustc_mir_dataflow/impls/
initialized.rs

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