Skip to main content

rustc_mir_transform/shim/
async_destructor_ctor.rs

1use rustc_hir::def_id::DefId;
2use rustc_hir::lang_items::LangItem;
3use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource};
4use rustc_index::{Idx, IndexVec};
5use rustc_middle::mir::{
6    BasicBlock, BasicBlockData, Body, Local, LocalDecl, MirSource, Operand, Place, Rvalue,
7    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
8};
9use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt};
10
11use super::*;
12use crate::patch::MirPatch;
13
14pub(super) fn build_async_destructor_ctor_shim<'tcx>(
15    tcx: TyCtxt<'tcx>,
16    def_id: DefId,
17    ty: Ty<'tcx>,
18) -> Body<'tcx> {
19    {
    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/shim/async_destructor_ctor.rs:19",
                        "rustc_mir_transform::shim::async_destructor_ctor",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
                        ::tracing_core::__macro_support::Option::Some(19u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim::async_destructor_ctor"),
                        ::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!("build_async_destructor_ctor_shim(def_id={0:?}, ty={1:?})",
                                                    def_id, ty) as &dyn Value))])
            });
    } else { ; }
};debug!("build_async_destructor_ctor_shim(def_id={:?}, ty={:?})", def_id, ty);
20    if true {
    match (&Some(def_id), &tcx.lang_items().async_drop_in_place_fn()) {
        (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!(Some(def_id), tcx.lang_items().async_drop_in_place_fn());
21    let generic_body = tcx.optimized_mir(def_id);
22    let args = tcx.mk_args(&[ty.into()]);
23    let mut body = EarlyBinder::bind(generic_body.clone()).instantiate(tcx, args).skip_norm_wip();
24
25    // Minimal shim passes except MentionedItems,
26    // it causes error "mentioned_items for DefId(...async_drop_in_place...) have already been set
27    pm::run_passes(
28        tcx,
29        &mut body,
30        &[
31            &simplify::SimplifyCfg::MakeShim,
32            &abort_unwinding_calls::AbortUnwindingCalls,
33            &add_call_guards::CriticalCallEdges,
34        ],
35        None,
36        pm::Optimizations::Allowed,
37    );
38    body
39}
40
41// build_drop_shim analog for async drop glue (for generated coroutine poll function)
42pub(super) fn build_async_drop_shim<'tcx>(
43    tcx: TyCtxt<'tcx>,
44    def_id: DefId,
45    ty: Ty<'tcx>,
46) -> Body<'tcx> {
47    {
    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/shim/async_destructor_ctor.rs:47",
                        "rustc_mir_transform::shim::async_destructor_ctor",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
                        ::tracing_core::__macro_support::Option::Some(47u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim::async_destructor_ctor"),
                        ::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!("build_async_drop_shim(def_id={0:?}, ty={1:?})",
                                                    def_id, ty) as &dyn Value))])
            });
    } else { ; }
};debug!("build_async_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
48    let ty::Coroutine(_, parent_args) = ty.kind() else {
49        ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
50    };
51    let typing_env = ty::TypingEnv::fully_monomorphized();
52
53    let drop_ty = parent_args.first().unwrap().expect_ty();
54    let drop_ptr_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, drop_ty);
55
56    if !tcx.is_coroutine(def_id) {
    ::core::panicking::panic("assertion failed: tcx.is_coroutine(def_id)")
};assert!(tcx.is_coroutine(def_id));
57    let coroutine_kind = tcx.coroutine_kind(def_id).unwrap();
58
59    if !#[allow(non_exhaustive_omitted_patterns)] match coroutine_kind {
            CoroutineKind::Desugared(CoroutineDesugaring::Async,
                CoroutineSource::Fn) => true,
            _ => false,
        } {
    ::core::panicking::panic("assertion failed: matches!(coroutine_kind,\n    CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn))")
};assert!(matches!(
60        coroutine_kind,
61        CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)
62    ));
63
64    let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
65    let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
66
67    let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
68    let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty());
69
70    let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([ty, resume_ty], tcx.types.unit));
71    let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
72
73    if !!drop_ty.is_coroutine() {
    ::core::panicking::panic("assertion failed: !drop_ty.is_coroutine()")
};assert!(!drop_ty.is_coroutine());
74    let span = tcx.def_span(def_id);
75    let source_info = SourceInfo::outermost(span);
76
77    // The first argument (index 0) which will be local 1 (after the return value).
78    let coroutine_layout = Place::from(Local::arg(0));
79    let coroutine_layout_dropee =
80        tcx.mk_place_field(coroutine_layout, FieldIdx::new(0), drop_ptr_ty);
81
82    let return_block = BasicBlock::new(1);
83    let mut blocks = IndexVec::with_capacity(2);
84    let block = |blocks: &mut IndexVec<_, _>, kind| {
85        blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
86    };
87    block(
88        &mut blocks,
89        if needs_sync_drop {
90            TerminatorKind::Drop {
91                place: tcx.mk_place_deref(coroutine_layout_dropee),
92                target: return_block,
93                unwind: UnwindAction::Continue,
94                replace: false,
95                drop: None,
96                async_fut: None,
97            }
98        } else {
99            TerminatorKind::Goto { target: return_block }
100        },
101    );
102    block(&mut blocks, TerminatorKind::Return);
103
104    let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlue(def_id, ty));
105    let mut body =
106        new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
107
108    body.coroutine = Some(Box::new(CoroutineInfo::initial(
109        coroutine_kind,
110        parent_args.as_coroutine().yield_ty(),
111        parent_args.as_coroutine().resume_ty(),
112    )));
113    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
114    if !needs_async_drop || drop_ty.references_error() {
115        // Returning noop body for types without `need async drop`
116        // (or sync Drop in case of !`need async drop` && `need drop`).
117        // And also for error types.
118        return body;
119    }
120
121    let dropee_ptr = Place::from(body.local_decls.push(LocalDecl::new(drop_ptr_ty, span)));
122    let st_kind = StatementKind::Assign(Box::new((
123        dropee_ptr,
124        Rvalue::Use(Operand::Move(coroutine_layout_dropee), WithRetag::Yes),
125    )));
126    body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
127
128    let dropline = body.basic_blocks.last_index();
129
130    let patch = {
131        let mut elaborator = DropShimElaborator {
132            body: &body,
133            patch: MirPatch::new(&body),
134            tcx,
135            typing_env,
136            produce_async_drops: true,
137        };
138        let dropee = tcx.mk_place_deref(dropee_ptr);
139        let resume_block = elaborator.patch.resume_block();
140        elaborate_drop(
141            &mut elaborator,
142            source_info,
143            dropee,
144            (),
145            return_block,
146            Unwind::To(resume_block),
147            START_BLOCK,
148            dropline,
149        );
150        elaborator.patch
151    };
152    patch.apply(&mut body);
153
154    body
155}
156
157// * For async drop a "normal" coroutine:
158// `async_drop_in_place<T>::{closure}.poll()` is converted into `T.future_drop_poll()`.
159// Every coroutine has its `poll` (calculate yourself a little further)
160// and its `future_drop_poll` (drop yourself a little further).
161//
162// * For async drop of "async drop coroutine" (`async_drop_in_place<T>::{closure}`):
163// Correct drop of such coroutine means normal execution of nested async drop.
164// async_drop(async_drop(T))::future_drop_poll() => async_drop(T)::poll().
165pub(super) fn build_future_drop_poll_shim<'tcx>(
166    tcx: TyCtxt<'tcx>,
167    def_id: DefId,
168    proxy_ty: Ty<'tcx>,
169    impl_ty: Ty<'tcx>,
170) -> Body<'tcx> {
171    let instance = ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty);
172    let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else {
173        ::rustc_middle::util::bug::bug_fmt(format_args!("build_future_drop_poll_shim not for coroutine impl type: ({0:?})",
        instance));bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", instance);
174    };
175
176    let span = tcx.def_span(def_id);
177
178    if tcx.is_async_drop_in_place_coroutine(*coroutine_def_id) {
179        build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, instance)
180    } else {
181        build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, instance)
182    }
183}
184
185// For async drop a "normal" coroutine:
186// `async_drop_in_place<T>::{closure}.poll()` is converted into `T.future_drop_poll()`.
187// Every coroutine has its `poll` (calculate yourself a little further)
188// and its `future_drop_poll` (drop yourself a little further).
189fn build_adrop_for_coroutine_shim<'tcx>(
190    tcx: TyCtxt<'tcx>,
191    proxy_ty: Ty<'tcx>,
192    impl_ty: Ty<'tcx>,
193    span: Span,
194    instance: ty::InstanceKind<'tcx>,
195) -> Body<'tcx> {
196    let ty::Coroutine(coroutine_def_id, impl_args) = impl_ty.kind() else {
197        ::rustc_middle::util::bug::bug_fmt(format_args!("build_adrop_for_coroutine_shim not for coroutine impl type: ({0:?})",
        instance));bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", instance);
198    };
199    let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
200    // taking _1.0 (impl from Pin)
201    let pin_proxy_layout_local = Local::new(1);
202    let source_info = SourceInfo::outermost(span);
203    // converting `(_1: Pin<&mut CorLayout>, _2: &mut Context<'_>) -> Poll<()>`
204    // into `(_1: Pin<&mut ProxyLayout>, _2: &mut Context<'_>) -> Poll<()>`
205    // let mut _x: &mut CorLayout = &mut *_1.0.0;
206    // Replace old _1.0 accesses into _x accesses;
207    let body = tcx.optimized_mir(*coroutine_def_id).future_drop_poll().unwrap();
208    let mut body: Body<'tcx> =
209        EarlyBinder::bind(body.clone()).instantiate(tcx, impl_args).skip_norm_wip();
210    body.source.instance = instance;
211    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
212    body.var_debug_info.clear();
213    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
214    let args = tcx.mk_args(&[proxy_ref.into()]);
215    let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args);
216
217    let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
218
219    let proxy_ref_local = body.local_decls.push(LocalDecl::new(proxy_ref, span));
220    let cor_ref_local = body.local_decls.push(LocalDecl::new(cor_ref, span));
221
222    FixProxyFutureDropVisitor { tcx, replace_to: cor_ref_local }.visit_body(&mut body);
223    // Now changing first arg from Pin<&mut ImplCoroutine> to Pin<&mut ProxyCoroutine>
224    body.local_decls[pin_proxy_layout_local] = LocalDecl::new(pin_proxy_ref, span);
225
226    {
227        let mut idx: usize = 0;
228        // _proxy = _1.0 : Pin<&mut ProxyLayout> ==> &mut ProxyLayout
229        let proxy_ref_place = Place::from(pin_proxy_layout_local)
230            .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
231        body.basic_blocks_mut()[START_BLOCK].statements.insert(
232            idx,
233            Statement::new(
234                source_info,
235                StatementKind::Assign(Box::new((
236                    Place::from(proxy_ref_local),
237                    Rvalue::Use(Operand::Copy(proxy_ref_place), WithRetag::Yes),
238                ))),
239            ),
240        );
241        idx += 1;
242
243        // _cor_ref_tmp = (*(*_proxy).0).0...
244        let mut cor_ref_tmp_local = proxy_ref_local;
245        proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
246            if ty != proxy_ty {
247                let ty_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
248                let impl_ptr_place = Place::from(cor_ref_tmp_local).project_deeper(
249                    &[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ref)],
250                    tcx,
251                );
252                cor_ref_tmp_local = body.local_decls.push(LocalDecl::new(ty_ref, span));
253                body.basic_blocks_mut()[START_BLOCK].statements.insert(
254                    idx,
255                    Statement::new(
256                        source_info,
257                        StatementKind::Assign(Box::new((
258                            Place::from(cor_ref_tmp_local),
259                            Rvalue::Use(Operand::Copy(impl_ptr_place), WithRetag::Yes),
260                        ))),
261                    ),
262                );
263                idx += 1;
264            }
265        });
266
267        // _cor_ref = cor_ref_tmp
268        body.basic_blocks_mut()[START_BLOCK].statements.insert(
269            idx,
270            Statement::new(
271                source_info,
272                StatementKind::Assign(Box::new((
273                    Place::from(cor_ref_local),
274                    Rvalue::Use(Operand::Move(Place::from(cor_ref_tmp_local)), WithRetag::Yes),
275                ))),
276            ),
277        );
278    }
279    body
280}
281
282// When dropping async drop coroutine, we continue its execution.
283// async_drop(async_drop(T))::future_drop_poll() => async_drop(T)::poll()
284fn build_adrop_for_adrop_shim<'tcx>(
285    tcx: TyCtxt<'tcx>,
286    proxy_ty: Ty<'tcx>,
287    impl_ty: Ty<'tcx>,
288    span: Span,
289    instance: ty::InstanceKind<'tcx>,
290) -> Body<'tcx> {
291    let source_info = SourceInfo::outermost(span);
292    let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
293    // taking _1.0 (impl from Pin)
294    let pin_proxy_layout_local = Local::new(1);
295    let proxy_ref_place = Place::from(pin_proxy_layout_local)
296        .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
297    let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
298
299    // ret_ty = `Poll<()>`
300    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span));
301    let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
302    // env_ty = `Pin<&mut proxy_ty>`
303    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
304    let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()]));
305    // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>`
306    let sig = tcx.mk_fn_sig_safe_rust_abi([env_ty, Ty::new_task_context(tcx)], ret_ty);
307    // This function will be called with pinned proxy coroutine layout.
308    // We need to extract `Arg0.0` to get proxy layout, and then get `.0`
309    // further to receive impl coroutine (may be needed)
310    let mut locals = local_decls_for_sig(&sig, span);
311    let mut blocks = IndexVec::with_capacity(3);
312
313    let proxy_ref_local = locals.push(LocalDecl::new(proxy_ref, span));
314
315    let call_bb = BasicBlock::new(1);
316    let return_bb = BasicBlock::new(2);
317
318    let mut statements = Vec::new();
319
320    statements.push(Statement::new(
321        source_info,
322        StatementKind::Assign(Box::new((
323            Place::from(proxy_ref_local),
324            Rvalue::Use(Operand::Copy(proxy_ref_place), WithRetag::Yes),
325        ))),
326    ));
327
328    let mut cor_ptr_local = proxy_ref_local;
329    proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
330        if ty != proxy_ty {
331            let ty_ptr = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
332            let impl_ptr_place = Place::from(cor_ptr_local)
333                .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
334            cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
335            // _cor_ptr = _proxy.0.0 (... .0)
336            statements.push(Statement::new(
337                source_info,
338                StatementKind::Assign(Box::new((
339                    Place::from(cor_ptr_local),
340                    Rvalue::Use(Operand::Copy(impl_ptr_place), WithRetag::Yes),
341                ))),
342            ));
343        }
344    });
345
346    // convert impl coroutine ptr into ref
347    let reborrow = Rvalue::Ref(
348        tcx.lifetimes.re_erased,
349        BorrowKind::Mut { kind: MutBorrowKind::Default },
350        tcx.mk_place_deref(Place::from(cor_ptr_local)),
351    );
352    let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
353    statements.push(Statement::new(
354        source_info,
355        StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
356    ));
357
358    // cor_pin_ty = `Pin<&mut cor_ref>`
359    let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
360    let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span)));
361
362    let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
363    // call Pin<FutTy>::new_unchecked(&mut impl_cor)
364    blocks.push(BasicBlockData::new_stmts(
365        statements,
366        Some(Terminator {
367            source_info,
368            kind: TerminatorKind::Call {
369                func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span),
370                args: [dummy_spanned(Operand::Move(cor_ref_place))].into(),
371                destination: cor_pin_place,
372                target: Some(call_bb),
373                unwind: UnwindAction::Continue,
374                call_source: CallSource::Misc,
375                fn_span: span,
376            },
377        }),
378        false,
379    ));
380    // When dropping async drop coroutine, we continue its execution:
381    // we call impl::poll (impl_layout, ctx)
382    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
383    let resume_ctx = Place::from(Local::new(2));
384    blocks.push(BasicBlockData::new(
385        Some(Terminator {
386            source_info,
387            kind: TerminatorKind::Call {
388                func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span),
389                args: [
390                    dummy_spanned(Operand::Move(cor_pin_place)),
391                    dummy_spanned(Operand::Move(resume_ctx)),
392                ]
393                .into(),
394                destination: Place::return_place(),
395                target: Some(return_bb),
396                unwind: UnwindAction::Continue,
397                call_source: CallSource::Misc,
398                fn_span: span,
399            },
400        }),
401        false,
402    ));
403    blocks.push(BasicBlockData::new(
404        Some(Terminator { source_info, kind: TerminatorKind::Return }),
405        false,
406    ));
407
408    let source = MirSource::from_instance(instance);
409    let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);
410    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
411    return body;
412}