Skip to main content

rustc_mir_transform/shim/
async_destructor_ctor.rs

1use rustc_attr_ir::lang_items::LangItem;
2use rustc_hir::def_id::DefId;
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::deref_separator::deref_finder;
13use crate::patch::MirPatch;
14
15const SELF_ARG: Local = Local::arg(0);
16
17pub(super) fn build_async_destructor_ctor_shim<'tcx>(
18    tcx: TyCtxt<'tcx>,
19    def_id: DefId,
20    ty: Ty<'tcx>,
21) -> Body<'tcx> {
22    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs:22",
                        "rustc_mir_transform::shim::async_destructor_ctor",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
                        ::tracing_core::__macro_support::Option::Some(22u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("build_async_destructor_ctor_shim(def_id={0:?}, ty={1:?})",
                                                    def_id, ty) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("build_async_destructor_ctor_shim(def_id={:?}, ty={:?})", def_id, ty);
23    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());
24    let generic_body = tcx.optimized_mir(def_id);
25    let args = tcx.mk_args(&[ty.into()]);
26    let mut body =
27        EarlyBinder::bind(tcx, generic_body.clone()).instantiate(tcx, args).skip_norm_wip();
28
29    // Minimal shim passes except MentionedItems,
30    // it causes error "mentioned_items for DefId(...async_drop_in_place...) have already been set
31    pm::run_passes(
32        tcx,
33        &mut body,
34        &[
35            &simplify::SimplifyCfg::MakeShim,
36            &abort_unwinding_calls::AbortUnwindingCalls,
37            &add_call_guards::CriticalCallEdges,
38        ],
39        None,
40    );
41    body
42}
43
44// build_drop_shim analog for async drop glue (for generated coroutine poll function)
45{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::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("build_async_drop_shim",
                                "rustc_mir_transform::shim::async_destructor_ctor",
                                ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
                                ::tracing_core::__macro_support::Option::Some(45u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim::async_destructor_ctor"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("def_id")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("def_id");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("ty")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("ty");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::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};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[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: Body<'tcx> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let ty::Coroutine(_, parent_args) =
                            ty.kind() else {
                                ::rustc_span::macros::bug_impl(None,
                                    format_args!("impossible case reached"),
                                    Location::caller());
                            };
                        let typing_env = ty::TypingEnv::fully_monomorphized();
                        let drop_ty = parent_args.first().unwrap().expect_ty();
                        let drop_ptr_ty =
                            Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, drop_ty);
                        if !tcx.is_coroutine(def_id) {
                            ::core::panicking::panic("assertion failed: tcx.is_coroutine(def_id)")
                        };
                        let coroutine_kind = tcx.coroutine_kind(def_id).unwrap();
                        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))")
                        };
                        let needs_async_drop =
                            drop_ty.needs_async_drop(tcx, typing_env);
                        let needs_sync_drop =
                            !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
                        let resume_adt =
                            tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy,
                                    DUMMY_SP));
                        let resume_ty =
                            Ty::new_adt(tcx, resume_adt, ty::GenericArgs::empty());
                        let fn_sig =
                            ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([ty,
                                            resume_ty], tcx.types.unit));
                        let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
                        if !!drop_ty.is_coroutine() {
                            ::core::panicking::panic("assertion failed: !drop_ty.is_coroutine()")
                        };
                        let span = tcx.def_span(def_id);
                        let source_info = SourceInfo::outermost(span);
                        let coroutine_layout = Place::from(SELF_ARG);
                        let coroutine_layout_dropee =
                            tcx.mk_place_field(coroutine_layout, FieldIdx::new(0),
                                drop_ptr_ty);
                        let return_block = BasicBlock::new(1);
                        let mut blocks = IndexVec::with_capacity(2);
                        let block =
                            |blocks: &mut IndexVec<_, _>, kind| -> BasicBlock
                                {
                                    blocks.push(BasicBlockData::new(Terminator {
                                                source_info,
                                                kind,
                                            }, false))
                                };
                        block(&mut blocks,
                            if needs_sync_drop {
                                TerminatorKind::Drop {
                                    place: tcx.mk_place_deref(coroutine_layout_dropee),
                                    target: return_block,
                                    unwind: UnwindAction::Continue,
                                    replace: false,
                                    drop: None,
                                }
                            } else { TerminatorKind::goto(return_block) });
                        let ret = block(&mut blocks, TerminatorKind::Return);
                        blocks[ret].statements.push(Statement::new(source_info,
                                StatementKind::Assign(Box::new((Place::return_place(),
                                            Rvalue::Use(Operand::zero_sized_constant(tcx.types.unit,
                                                    span), WithRetag::Yes))))));
                        let source =
                            MirSource::from_shim(ty::ShimKind::AsyncDropGlue(def_id,
                                    ty));
                        let mut body =
                            new_body(source, blocks, local_decls_for_sig(&sig, span),
                                sig.inputs().len(), span);
                        body.coroutine =
                            Some(Box::new(CoroutineInfo::initial(coroutine_kind,
                                        parent_args.as_coroutine().yield_ty(),
                                        parent_args.as_coroutine().resume_ty())));
                        body.phase = MirPhase::Runtime(RuntimePhase::Initial);
                        if needs_async_drop && !drop_ty.references_error() {
                            let dropee_ptr =
                                Place::from(body.local_decls.push(LocalDecl::new(drop_ptr_ty,
                                            span)));
                            let st_kind =
                                StatementKind::Assign(Box::new((dropee_ptr,
                                            Rvalue::Use(Operand::Move(coroutine_layout_dropee),
                                                WithRetag::Yes))));
                            body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info,
                                    st_kind));
                            let dropline = body.basic_blocks.last_index();
                            let patch =
                                {
                                    let mut elaborator =
                                        DropShimElaborator {
                                            body: &body,
                                            patch: MirPatch::new(&body),
                                            tcx,
                                            typing_env,
                                            produce_async_drops: true,
                                        };
                                    let dropee = tcx.mk_place_deref(dropee_ptr);
                                    let resume_block = elaborator.patch.resume_block();
                                    elaborate_drop(&mut elaborator, source_info, dropee, (),
                                        return_block, Unwind::To(resume_block), START_BLOCK,
                                        dropline);
                                    elaborator.patch
                                };
                            patch.apply(&mut body);
                        }
                        deref_finder(tcx, &mut body, false);
                        body
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs:45",
                        "rustc_mir_transform::shim::async_destructor_ctor",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5b7b37aefcb5b2fba3c2392bc9065b9e4602d494/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs"),
                        ::tracing_core::__macro_support::Option::Some(45u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim::async_destructor_ctor"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[tracing::instrument(level = "trace", skip(tcx), ret)]
46pub(super) fn build_async_drop_shim<'tcx>(
47    tcx: TyCtxt<'tcx>,
48    def_id: DefId,
49    ty: Ty<'tcx>,
50) -> Body<'tcx> {
51    let ty::Coroutine(_, parent_args) = ty.kind() else {
52        bug!();
53    };
54    let typing_env = ty::TypingEnv::fully_monomorphized();
55
56    let drop_ty = parent_args.first().unwrap().expect_ty();
57    let drop_ptr_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, drop_ty);
58
59    assert!(tcx.is_coroutine(def_id));
60    let coroutine_kind = tcx.coroutine_kind(def_id).unwrap();
61
62    assert!(matches!(
63        coroutine_kind,
64        CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)
65    ));
66
67    let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
68    let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
69
70    let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
71    let resume_ty = Ty::new_adt(tcx, resume_adt, ty::GenericArgs::empty());
72
73    let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi([ty, resume_ty], tcx.types.unit));
74    let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
75
76    assert!(!drop_ty.is_coroutine());
77    let span = tcx.def_span(def_id);
78    let source_info = SourceInfo::outermost(span);
79
80    // The first argument (index 0) which will be local 1 (after the return value).
81    let coroutine_layout = Place::from(SELF_ARG);
82    let coroutine_layout_dropee =
83        tcx.mk_place_field(coroutine_layout, FieldIdx::new(0), drop_ptr_ty);
84
85    let return_block = BasicBlock::new(1);
86    let mut blocks = IndexVec::with_capacity(2);
87    let block = |blocks: &mut IndexVec<_, _>, kind| -> BasicBlock {
88        blocks.push(BasicBlockData::new(Terminator { source_info, kind }, false))
89    };
90    block(
91        &mut blocks,
92        if needs_sync_drop {
93            TerminatorKind::Drop {
94                place: tcx.mk_place_deref(coroutine_layout_dropee),
95                target: return_block,
96                unwind: UnwindAction::Continue,
97                replace: false,
98                drop: None,
99            }
100        } else {
101            TerminatorKind::goto(return_block)
102        },
103    );
104    let ret = block(&mut blocks, TerminatorKind::Return);
105    blocks[ret].statements.push(Statement::new(
106        source_info,
107        StatementKind::Assign(Box::new((
108            Place::return_place(),
109            Rvalue::Use(Operand::zero_sized_constant(tcx.types.unit, span), WithRetag::Yes),
110        ))),
111    ));
112
113    let source = MirSource::from_shim(ty::ShimKind::AsyncDropGlue(def_id, ty));
114    let mut body =
115        new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
116
117    body.coroutine = Some(Box::new(CoroutineInfo::initial(
118        coroutine_kind,
119        parent_args.as_coroutine().yield_ty(),
120        parent_args.as_coroutine().resume_ty(),
121    )));
122    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
123
124    // Returning noop body for types without `need async drop`
125    // (or sync Drop in case of !`need async drop` && `need drop`).
126    // And also for error types.
127    if needs_async_drop && !drop_ty.references_error() {
128        let dropee_ptr = Place::from(body.local_decls.push(LocalDecl::new(drop_ptr_ty, span)));
129        let st_kind = StatementKind::Assign(Box::new((
130            dropee_ptr,
131            Rvalue::Use(Operand::Move(coroutine_layout_dropee), WithRetag::Yes),
132        )));
133        body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
134
135        let dropline = body.basic_blocks.last_index();
136
137        let patch = {
138            let mut elaborator = DropShimElaborator {
139                body: &body,
140                patch: MirPatch::new(&body),
141                tcx,
142                typing_env,
143                produce_async_drops: true,
144            };
145            let dropee = tcx.mk_place_deref(dropee_ptr);
146            let resume_block = elaborator.patch.resume_block();
147            elaborate_drop(
148                &mut elaborator,
149                source_info,
150                dropee,
151                (),
152                return_block,
153                Unwind::To(resume_block),
154                START_BLOCK,
155                dropline,
156            );
157            elaborator.patch
158        };
159        patch.apply(&mut body);
160    }
161
162    // We did not bother respecting deref separation, do it here.
163    deref_finder(tcx, &mut body, false);
164
165    body
166}
167
168// * For async drop a "normal" coroutine:
169// `async_drop_in_place<T>::{closure}.poll()` is converted into `T.future_drop_poll()`.
170// Every coroutine has its `poll` (calculate yourself a little further)
171// and its `future_drop_poll` (drop yourself a little further).
172//
173// * For async drop of "async drop coroutine" (`async_drop_in_place<T>::{closure}`):
174// Correct drop of such coroutine means normal execution of nested async drop.
175// async_drop(async_drop(T))::future_drop_poll() => async_drop(T)::poll().
176pub(super) fn build_future_drop_poll_shim<'tcx>(
177    tcx: TyCtxt<'tcx>,
178    def_id: DefId,
179    proxy_ty: Ty<'tcx>,
180    impl_ty: Ty<'tcx>,
181) -> Body<'tcx> {
182    let shim = ty::ShimKind::FutureDropPoll(def_id, proxy_ty, impl_ty);
183    let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else {
184        ::rustc_span::macros::bug_impl(None,
    format_args!("build_future_drop_poll_shim not for coroutine impl type: ({0:?})",
        shim), Location::caller());bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", shim);
185    };
186
187    let span = tcx.def_span(def_id);
188
189    if tcx.is_async_drop_in_place_coroutine(*coroutine_def_id) {
190        build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, shim)
191    } else {
192        build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, shim)
193    }
194}
195
196// For async drop a "normal" coroutine:
197// `async_drop_in_place<T>::{closure}.poll()` is converted into `T.future_drop_poll()`.
198// Every coroutine has its `poll` (calculate yourself a little further)
199// and its `future_drop_poll` (drop yourself a little further).
200fn build_adrop_for_coroutine_shim<'tcx>(
201    tcx: TyCtxt<'tcx>,
202    proxy_ty: Ty<'tcx>,
203    impl_ty: Ty<'tcx>,
204    span: Span,
205    shim: ty::ShimKind<'tcx>,
206) -> Body<'tcx> {
207    let ty::Coroutine(coroutine_def_id, impl_args) = impl_ty.kind() else {
208        ::rustc_span::macros::bug_impl(None,
    format_args!("build_adrop_for_coroutine_shim not for coroutine impl type: ({0:?})",
        shim), Location::caller());bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", shim);
209    };
210    let ty::Coroutine(_, id_args) = *tcx.type_of(*coroutine_def_id).skip_binder().kind() else {
211        ::rustc_span::macros::bug_impl(None, format_args!("impossible case reached"),
    Location::caller())bug!()
212    };
213    let source_info = SourceInfo::outermost(span);
214
215    // If the kind tys differ, we must use the by-move body
216    let def_id = if id_args.as_coroutine().kind_ty() == impl_args.as_coroutine().kind_ty() {
217        *coroutine_def_id
218    } else {
219        {
    match (&impl_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
            &ty::ClosureKind::FnOnce) {
        (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);
            }
        }
    }
};assert_eq!(
220            impl_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
221            ty::ClosureKind::FnOnce
222        );
223
224        tcx.coroutine_by_move_body_def_id(*coroutine_def_id)
225    };
226    let body = tcx.optimized_mir(def_id).future_drop_poll().unwrap();
227    let mut body: Body<'tcx> =
228        EarlyBinder::bind(tcx, body.clone()).instantiate(tcx, impl_args).skip_norm_wip();
229    body.source.instance = ty::InstanceKind::Shim(shim);
230    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
231    body.var_debug_info.clear();
232
233    // converting `(_1: Pin<&mut CorLayout>, _2: &mut Context<'_>) -> Poll<()>`
234    // into `(_1: Pin<&mut ProxyLayout>, _2: &mut Context<'_>) -> Poll<()>`
235    // let mut _x: &mut CorLayout = &mut *_1.0.0;
236    // Replace old _1.0 accesses into _x accesses;
237    let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
238
239    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
240    let args = tcx.mk_args(&[proxy_ref.into()]);
241    let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args);
242
243    let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
244    let cor_ref_local = body.local_decls.push(LocalDecl::new(cor_ref, span));
245
246    FixProxyFutureDropVisitor { tcx, replace_to: cor_ref_local }.visit_body(&mut body);
247
248    // Now changing first arg from Pin<&mut ImplCoroutine> to Pin<&mut ProxyCoroutine>
249    body.local_decls[SELF_ARG] = LocalDecl::new(pin_proxy_ref, span);
250
251    // Build the projection to assign `cor_ref_local = _1.<projection>`.
252    let mut pin_proxy_to_cor_projection = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [PlaceElem::Field(FieldIdx::ZERO, proxy_ref)]))vec![
253        // _1.0 : Pin<&mut ProxyLayout> ==> &mut ProxyLayout
254        PlaceElem::Field(FieldIdx::ZERO, proxy_ref),
255    ];
256
257    // _cor_ref_tmp = (*(*_proxy).0).0...
258    proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
259        if ty != proxy_ty {
260            let ty_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
261            pin_proxy_to_cor_projection.push(PlaceElem::Deref);
262            pin_proxy_to_cor_projection.push(PlaceElem::Field(FieldIdx::ZERO, ty_ref));
263        }
264    });
265
266    // _cor_ref = cor_ref_tmp
267    let projected_pin = Place::from(SELF_ARG).project_deeper(&pin_proxy_to_cor_projection, tcx);
268    body.basic_blocks_mut()[START_BLOCK].statements.insert(
269        0,
270        Statement::new(
271            source_info,
272            StatementKind::Assign(Box::new((
273                Place::from(cor_ref_local),
274                Rvalue::Use(Operand::Move(projected_pin), WithRetag::Yes),
275            ))),
276        ),
277    );
278
279    // We did not bother respecting deref separation, do it here.
280    deref_finder(tcx, &mut body, false);
281
282    return body;
283
284    /// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> accesses
285    struct FixProxyFutureDropVisitor<'tcx> {
286        tcx: TyCtxt<'tcx>,
287        replace_to: Local,
288    }
289
290    impl<'tcx> MutVisitor<'tcx> for FixProxyFutureDropVisitor<'tcx> {
291        fn tcx(&self) -> TyCtxt<'tcx> {
292            self.tcx
293        }
294
295        fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _: Location) {
296            if place.local == SELF_ARG
297                && let Some((first, rest)) = place.projection.split_first()
298            {
299                if !#[allow(non_exhaustive_omitted_patterns)] match first {
            ProjectionElem::Field(FieldIdx::ZERO, _) => true,
            _ => false,
        } {
    ::core::panicking::panic("assertion failed: matches!(first, ProjectionElem::Field(FieldIdx::ZERO, _))")
};assert!(matches!(first, ProjectionElem::Field(FieldIdx::ZERO, _)));
300                *place = Place::from(self.replace_to).project_deeper(rest, self.tcx);
301            }
302        }
303    }
304}
305
306// When dropping async drop coroutine, we continue its execution.
307// async_drop(async_drop(T))::future_drop_poll() => async_drop(T)::poll()
308fn build_adrop_for_adrop_shim<'tcx>(
309    tcx: TyCtxt<'tcx>,
310    proxy_ty: Ty<'tcx>,
311    impl_ty: Ty<'tcx>,
312    span: Span,
313    shim: ty::ShimKind<'tcx>,
314) -> Body<'tcx> {
315    let source_info = SourceInfo::outermost(span);
316    let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty);
317    // taking _1.0 (impl from Pin)
318    let proxy_ref_place =
319        Place::from(SELF_ARG).project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
320    let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
321
322    // ret_ty = `Poll<()>`
323    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span));
324    let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
325    // env_ty = `Pin<&mut proxy_ty>`
326    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
327    let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()]));
328    // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>`
329    let sig = tcx.mk_fn_sig_safe_rust_abi([env_ty, Ty::new_task_context(tcx)], ret_ty);
330    // This function will be called with pinned proxy coroutine layout.
331    // We need to extract `Arg0.0` to get proxy layout, and then get `.0`
332    // further to receive impl coroutine (may be needed)
333    let mut locals = local_decls_for_sig(&sig, span);
334    let mut blocks = IndexVec::with_capacity(3);
335
336    let proxy_ref_local = locals.push(LocalDecl::new(proxy_ref, span));
337
338    let call_bb = BasicBlock::new(1);
339    let return_bb = BasicBlock::new(2);
340
341    let mut statements = Vec::new();
342
343    statements.push(Statement::new(
344        source_info,
345        StatementKind::Assign(Box::new((
346            Place::from(proxy_ref_local),
347            Rvalue::Use(Operand::Copy(proxy_ref_place), WithRetag::Yes),
348        ))),
349    ));
350
351    let mut cor_ptr_local = proxy_ref_local;
352    proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
353        if ty != proxy_ty {
354            let ty_ptr = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
355            let impl_ptr_place = Place::from(cor_ptr_local)
356                .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
357            cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
358            // _cor_ptr = _proxy.0.0 (... .0)
359            statements.push(Statement::new(
360                source_info,
361                StatementKind::Assign(Box::new((
362                    Place::from(cor_ptr_local),
363                    Rvalue::Use(Operand::Copy(impl_ptr_place), WithRetag::Yes),
364                ))),
365            ));
366        }
367    });
368
369    // convert impl coroutine ptr into ref
370    let reborrow = Rvalue::Ref(
371        tcx.lifetimes.re_erased,
372        BorrowKind::Mut { kind: MutBorrowKind::Default },
373        tcx.mk_place_deref(Place::from(cor_ptr_local)),
374    );
375    let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
376    statements.push(Statement::new(
377        source_info,
378        StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
379    ));
380
381    // cor_pin_ty = `Pin<&mut cor_ref>`
382    let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
383    let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span)));
384
385    let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
386    // call Pin<FutTy>::new_unchecked(&mut impl_cor)
387    blocks.push(BasicBlockData::new_stmts(
388        statements,
389        Terminator {
390            source_info,
391            kind: TerminatorKind::Call {
392                func: Operand::function_handle(tcx, pin_fn, &[cor_ref.into()], span),
393                args: [dummy_spanned(Operand::Move(cor_ref_place))].into(),
394                destination: cor_pin_place,
395                target: Some(call_bb),
396                unwind: UnwindAction::Continue,
397                call_source: CallSource::Misc,
398                fn_span: span,
399            },
400        },
401        false,
402    ));
403    // When dropping async drop coroutine, we continue its execution:
404    // we call impl::poll (impl_layout, ctx)
405    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
406    let resume_ctx = Place::from(Local::new(2));
407    blocks.push(BasicBlockData::new(
408        Terminator {
409            source_info,
410            kind: TerminatorKind::Call {
411                func: Operand::function_handle(tcx, poll_fn, &[impl_ty.into()], span),
412                args: [
413                    dummy_spanned(Operand::Move(cor_pin_place)),
414                    dummy_spanned(Operand::Move(resume_ctx)),
415                ]
416                .into(),
417                destination: Place::return_place(),
418                target: Some(return_bb),
419                unwind: UnwindAction::Continue,
420                call_source: CallSource::Misc,
421                fn_span: span,
422            },
423        },
424        false,
425    ));
426    blocks
427        .push(BasicBlockData::new(Terminator { source_info, kind: TerminatorKind::Return }, false));
428
429    let source = MirSource::from_shim(shim);
430    let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);
431    body.phase = MirPhase::Runtime(RuntimePhase::Initial);
432    return body;
433}