Skip to main content

rustc_mir_transform/
patch.rs

1use rustc_data_structures::fx::FxHashMap;
2use rustc_data_structures::thin_vec::ThinVec;
3use rustc_index::Idx;
4use rustc_middle::mir::*;
5use rustc_middle::ty::Ty;
6use rustc_span::Span;
7use tracing::debug;
8
9/// This struct lets you "patch" a MIR body, i.e. modify it. You can queue up
10/// various changes, such as the addition of new statements and basic blocks
11/// and replacement of terminators, and then apply the queued changes all at
12/// once with `apply`. This is useful for MIR transformation passes.
13pub(crate) struct MirPatch<'tcx> {
14    term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>,
15    /// Set of statements that should be replaced by `Nop`.
16    nop_statements: Vec<Location>,
17    new_blocks: Vec<BasicBlockData<'tcx>>,
18    new_statements: Vec<(Location, StatementKind<'tcx>)>,
19    new_locals: Vec<LocalDecl<'tcx>>,
20    resume_block: Option<BasicBlock>,
21    // Only for unreachable in cleanup path.
22    unreachable_cleanup_block: Option<BasicBlock>,
23    // Only for unreachable not in cleanup path.
24    unreachable_no_cleanup_block: Option<BasicBlock>,
25    // Cached block for UnwindTerminate (with reason)
26    terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
27    body_span: Span,
28    /// The number of locals at the start of the transformation. New locals
29    /// get appended at the end.
30    next_local: usize,
31    /// The number of blocks at the start of the transformation. New blocks
32    /// get appended at the end.
33    next_block: usize,
34}
35
36impl<'tcx> MirPatch<'tcx> {
37    /// Creates a new, empty patch.
38    pub(crate) fn new(body: &Body<'tcx>) -> Self {
39        let mut result = MirPatch {
40            term_patch_map: Default::default(),
41            nop_statements: ::alloc::vec::Vec::new()vec![],
42            new_blocks: ::alloc::vec::Vec::new()vec![],
43            new_statements: ::alloc::vec::Vec::new()vec![],
44            new_locals: ::alloc::vec::Vec::new()vec![],
45            next_local: body.local_decls.len(),
46            next_block: body.basic_blocks.len(),
47            resume_block: None,
48            unreachable_cleanup_block: None,
49            unreachable_no_cleanup_block: None,
50            terminate_block: None,
51            body_span: body.span,
52        };
53
54        for (bb, block) in body.basic_blocks.iter_enumerated() {
55            // Check if we already have a resume block
56            if #[allow(non_exhaustive_omitted_patterns)] match block.terminator().kind {
    TerminatorKind::UnwindResume => true,
    _ => false,
}matches!(block.terminator().kind, TerminatorKind::UnwindResume)
57                && block.statements.is_empty()
58            {
59                result.resume_block = Some(bb);
60                continue;
61            }
62
63            // Check if we already have an unreachable block
64            if #[allow(non_exhaustive_omitted_patterns)] match block.terminator().kind {
    TerminatorKind::Unreachable => true,
    _ => false,
}matches!(block.terminator().kind, TerminatorKind::Unreachable)
65                && block.statements.is_empty()
66            {
67                if block.is_cleanup {
68                    result.unreachable_cleanup_block = Some(bb);
69                } else {
70                    result.unreachable_no_cleanup_block = Some(bb);
71                }
72                continue;
73            }
74
75            // Check if we already have a terminate block
76            if let TerminatorKind::UnwindTerminate(reason) = block.terminator().kind
77                && block.statements.is_empty()
78            {
79                result.terminate_block = Some((bb, reason));
80                continue;
81            }
82        }
83
84        result
85    }
86
87    pub(crate) fn resume_block(&mut self) -> BasicBlock {
88        if let Some(bb) = self.resume_block {
89            return bb;
90        }
91
92        let bb = self.new_block(BasicBlockData::new(
93            Some(Terminator {
94                source_info: SourceInfo::outermost(self.body_span),
95                kind: TerminatorKind::UnwindResume,
96                attributes: ThinVec::new(),
97            }),
98            true,
99        ));
100        self.resume_block = Some(bb);
101        bb
102    }
103
104    pub(crate) fn unreachable_cleanup_block(&mut self) -> BasicBlock {
105        if let Some(bb) = self.unreachable_cleanup_block {
106            return bb;
107        }
108
109        let bb = self.new_block(BasicBlockData::new(
110            Some(Terminator {
111                source_info: SourceInfo::outermost(self.body_span),
112                kind: TerminatorKind::Unreachable,
113                attributes: ThinVec::new(),
114            }),
115            true,
116        ));
117        self.unreachable_cleanup_block = Some(bb);
118        bb
119    }
120
121    pub(crate) fn unreachable_no_cleanup_block(&mut self) -> BasicBlock {
122        if let Some(bb) = self.unreachable_no_cleanup_block {
123            return bb;
124        }
125
126        let bb = self.new_block(BasicBlockData::new(
127            Some(Terminator {
128                source_info: SourceInfo::outermost(self.body_span),
129                kind: TerminatorKind::Unreachable,
130                attributes: ThinVec::new(),
131            }),
132            false,
133        ));
134        self.unreachable_no_cleanup_block = Some(bb);
135        bb
136    }
137
138    pub(crate) fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
139        if let Some((cached_bb, cached_reason)) = self.terminate_block
140            && reason == cached_reason
141        {
142            return cached_bb;
143        }
144
145        let bb = self.new_block(BasicBlockData::new(
146            Some(Terminator {
147                source_info: SourceInfo::outermost(self.body_span),
148                kind: TerminatorKind::UnwindTerminate(reason),
149                attributes: ThinVec::new(),
150            }),
151            true,
152        ));
153        self.terminate_block = Some((bb, reason));
154        bb
155    }
156
157    /// Has a replacement of this block's terminator been queued in this patch?
158    pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool {
159        self.term_patch_map.contains_key(&bb)
160    }
161
162    /// Universal getter for block data, either it is in 'old' blocks or in patched ones
163    pub(crate) fn block<'a>(
164        &'a self,
165        body: &'a Body<'tcx>,
166        bb: BasicBlock,
167    ) -> &'a BasicBlockData<'tcx> {
168        match bb.index().checked_sub(body.basic_blocks.len()) {
169            Some(new) => &self.new_blocks[new],
170            None => &body[bb],
171        }
172    }
173
174    /// Queues the addition of a new temporary with additional local info.
175    pub(crate) fn new_local_with_info(
176        &mut self,
177        ty: Ty<'tcx>,
178        span: Span,
179        local_info: LocalInfo<'tcx>,
180    ) -> Local {
181        let index = self.next_local + self.new_locals.len();
182        let mut new_decl = LocalDecl::new(ty, span);
183        **new_decl.local_info.as_mut().unwrap_crate_local() = local_info;
184        self.new_locals.push(new_decl);
185        Local::new(index)
186    }
187
188    /// Queues the addition of a new temporary.
189    pub(crate) fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
190        let index = self.next_local + self.new_locals.len();
191        self.new_locals.push(LocalDecl::new(ty, span));
192        Local::new(index)
193    }
194
195    /// Returns the type of a local that's newly-added in the patch.
196    pub(crate) fn local_ty(&self, local: Local) -> Ty<'tcx> {
197        let local = local.as_usize();
198        if !(local < self.next_local + self.new_locals.len()) {
    ::core::panicking::panic("assertion failed: local < self.next_local + self.new_locals.len()")
};assert!(local < self.next_local + self.new_locals.len());
199        let new_local_idx = local - self.next_local;
200        self.new_locals[new_local_idx].ty
201    }
202
203    /// Queues the addition of a new basic block.
204    pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
205        let block = BasicBlock::from_usize(self.next_block + self.new_blocks.len());
206        {
    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_transform/src/patch.rs:206",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(206u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: new_block: {0:?}: {1:?}",
                                                    block, data) as &dyn Value))])
            });
    } else { ; }
};debug!("MirPatch: new_block: {:?}: {:?}", block, data);
207        self.new_blocks.push(data);
208        block
209    }
210
211    /// Queues the replacement of a block's terminator.
212    pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
213        if !!self.term_patch_map.contains_key(&block) {
    ::core::panicking::panic("assertion failed: !self.term_patch_map.contains_key(&block)")
};assert!(!self.term_patch_map.contains_key(&block));
214        {
    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_transform/src/patch.rs:214",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(214u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: patch_terminator({0:?}, {1:?})",
                                                    block, new) as &dyn Value))])
            });
    } else { ; }
};debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
215        self.term_patch_map.insert(block, new);
216    }
217
218    /// Mark given statement to be replaced by a `Nop`.
219    ///
220    /// This method only works on statements from the initial body, and cannot be used to remove
221    /// statements from `add_statement` or `add_assign`.
222    #[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("nop_statement",
                                    "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                                    ::tracing_core::__macro_support::Option::Some(222u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                                    ::tracing_core::field::FieldSet::new(&["loc"],
                                        ::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(&loc)
                                                            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;
        }
        { self.nop_statements.push(loc); }
    }
}#[tracing::instrument(level = "debug", skip(self))]
223    pub(crate) fn nop_statement(&mut self, loc: Location) {
224        self.nop_statements.push(loc);
225    }
226
227    /// Queues the insertion of a statement at a given location. The statement
228    /// currently at that location, and all statements that follow, are shifted
229    /// down. If multiple statements are queued for addition at the same
230    /// location, the final statement order after calling `apply` will match
231    /// the queue insertion order.
232    ///
233    /// E.g. if we have `s0` at location `loc` and do these calls:
234    ///
235    ///   p.add_statement(loc, s1);
236    ///   p.add_statement(loc, s2);
237    ///   p.apply(body);
238    ///
239    /// then the final order will be `s1, s2, s0`, with `s1` at `loc`.
240    pub(crate) fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) {
241        {
    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_transform/src/patch.rs:241",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(241u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: add_statement({0:?}, {1:?})",
                                                    loc, stmt) as &dyn Value))])
            });
    } else { ; }
};debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt);
242        self.new_statements.push((loc, stmt));
243    }
244
245    /// Like `add_statement`, but specialized for assignments.
246    pub(crate) fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
247        self.add_statement(loc, StatementKind::Assign(Box::new((place, rv))));
248    }
249
250    /// Applies the queued changes.
251    pub(crate) fn apply(self, body: &mut Body<'tcx>) {
252        {
    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_transform/src/patch.rs:252",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(252u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: {0:?} new temps, starting from index {1}: {2:?}",
                                                    self.new_locals.len(), body.local_decls.len(),
                                                    self.new_locals) as &dyn Value))])
            });
    } else { ; }
};debug!(
253            "MirPatch: {:?} new temps, starting from index {}: {:?}",
254            self.new_locals.len(),
255            body.local_decls.len(),
256            self.new_locals
257        );
258        {
    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_transform/src/patch.rs:258",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(258u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: {0} new blocks, starting from index {1}",
                                                    self.new_blocks.len(), body.basic_blocks.len()) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
259            "MirPatch: {} new blocks, starting from index {}",
260            self.new_blocks.len(),
261            body.basic_blocks.len()
262        );
263        if true {
    match (&self.next_block, &body.basic_blocks.len()) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    };
};debug_assert_eq!(self.next_block, body.basic_blocks.len());
264        let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() {
265            body.basic_blocks.as_mut_preserves_cfg()
266        } else {
267            body.basic_blocks.as_mut()
268        };
269        bbs.extend(self.new_blocks);
270        body.local_decls.extend(self.new_locals);
271
272        for loc in self.nop_statements {
273            bbs[loc.block].statements[loc.statement_index].make_nop(true);
274        }
275
276        let mut new_statements = self.new_statements;
277
278        // This must be a stable sort to provide the ordering described in the
279        // comment for `add_statement`.
280        new_statements.sort_by_key(|s| s.0);
281
282        let mut delta = 0;
283        let mut last_bb = START_BLOCK;
284        for (mut loc, stmt) in new_statements {
285            if loc.block != last_bb {
286                delta = 0;
287                last_bb = loc.block;
288            }
289            {
    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_transform/src/patch.rs:289",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(289u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: adding statement {0:?} at loc {1:?}+{2}",
                                                    stmt, loc, delta) as &dyn Value))])
            });
    } else { ; }
};debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
290            loc.statement_index += delta;
291            let source_info = Self::source_info_for_index(&bbs[loc.block], loc);
292            bbs[loc.block]
293                .statements
294                .insert(loc.statement_index, Statement::new(source_info, stmt));
295            delta += 1;
296        }
297
298        // The order in which we patch terminators does not change the result.
299        #[allow(rustc::potential_query_instability)]
300        for (src, patch) in self.term_patch_map {
301            {
    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_transform/src/patch.rs:301",
                        "rustc_mir_transform::patch", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/patch.rs"),
                        ::tracing_core::__macro_support::Option::Some(301u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::patch"),
                        ::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!("MirPatch: patching block {0:?}",
                                                    src) as &dyn Value))])
            });
    } else { ; }
};debug!("MirPatch: patching block {:?}", src);
302            let bb = &mut bbs[src];
303            if let TerminatorKind::Unreachable = patch {
304                bb.statements.clear();
305            }
306            bb.terminator_mut().kind = patch;
307        }
308    }
309
310    fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
311        match data.statements.get(loc.statement_index) {
312            Some(stmt) => stmt.source_info,
313            None => data.terminator().source_info,
314        }
315    }
316
317    pub(crate) fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo {
318        let data = self.block(body, loc.block);
319        Self::source_info_for_index(data, loc)
320    }
321}