Skip to main content

rustc_mir_transform/
patch.rs

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