Skip to main content

rustc_mir_transform/
shim.rs

1use std::{assert_matches, fmt, iter};
2
3use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx};
4use rustc_data_structures::thin_vec::ThinVec;
5use rustc_hir as hir;
6use rustc_hir::def_id::DefId;
7use rustc_hir::lang_items::LangItem;
8use rustc_index::{Idx, IndexVec};
9use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
10use rustc_middle::mir::*;
11use rustc_middle::query::Providers;
12use rustc_middle::ty::{
13    self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt, Unnormalized,
14};
15use rustc_middle::{bug, span_bug};
16use rustc_span::{DUMMY_SP, Span, Spanned, dummy_spanned};
17use tracing::{debug, instrument};
18
19use crate::deref_separator::deref_finder;
20use crate::elaborate_drop::{DropElaborator, DropFlagMode, DropStyle, Unwind, elaborate_drop};
21use crate::patch::MirPatch;
22use crate::{
23    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, inline, instsimplify,
24    mentioned_items, pass_manager as pm, remove_noop_landing_pads, run_optimization_passes,
25    simplify,
26};
27
28mod async_destructor_ctor;
29
30pub(super) fn provide(providers: &mut Providers) {
31    providers.mir_shims = make_shim;
32}
33
34fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> {
35    {
    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.rs:35",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(35u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?})",
                                                    instance) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?})", instance);
36
37    let mut result = match instance {
38        ty::InstanceKind::Item(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("item {0:?} passed to make_shim",
        instance))bug!("item {:?} passed to make_shim", instance),
39        ty::InstanceKind::VTableShim(def_id) => {
40            let adjustment = Adjustment::Deref { source: DerefSource::MutPtr };
41            build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
42        }
43        ty::InstanceKind::FnPtrShim(def_id, ty) => {
44            let trait_ = tcx.parent(def_id);
45            // Supports `Fn` or `async Fn` traits.
46            let adjustment = match tcx
47                .fn_trait_kind_from_def_id(trait_)
48                .or_else(|| tcx.async_fn_trait_kind_from_def_id(trait_))
49            {
50                Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
51                Some(ty::ClosureKind::Fn) => Adjustment::Deref { source: DerefSource::ImmRef },
52                Some(ty::ClosureKind::FnMut) => Adjustment::Deref { source: DerefSource::MutRef },
53                None => ::rustc_middle::util::bug::bug_fmt(format_args!("fn pointer {0:?} is not an fn",
        ty))bug!("fn pointer {:?} is not an fn", ty),
54            };
55
56            build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
57        }
58        // We are generating a call back to our def-id, which the
59        // codegen backend knows to turn to an actual call, be it
60        // a virtual call, or a direct call to a function for which
61        // indirect calls must be codegen'd differently than direct ones
62        // (such as `#[track_caller]`).
63        ty::InstanceKind::ReifyShim(def_id, _) => {
64            build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
65        }
66        ty::InstanceKind::ClosureOnceShim { call_once: _, closure: _, track_caller: _ } => {
67            let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP);
68            let call_mut = tcx
69                .associated_items(fn_mut)
70                .in_definition_order()
71                .find(|it| it.is_fn())
72                .unwrap()
73                .def_id;
74
75            build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
76        }
77
78        ty::InstanceKind::ConstructCoroutineInClosureShim {
79            coroutine_closure_def_id,
80            receiver_by_ref,
81        } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref),
82
83        ty::InstanceKind::DropGlue(def_id, ty) => {
84            // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end
85            // of this function. Is this intentional?
86            if let Some(&ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) {
87                let coroutine_body = tcx.optimized_mir(coroutine_def_id);
88
89                let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
90                else {
91                    ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
92                };
93
94                // If this is a regular coroutine, grab its drop shim. If this is a coroutine
95                // that comes from a coroutine-closure, and the kind ty differs from the "maximum"
96                // kind that it supports, then grab the appropriate drop shim. This ensures that
97                // the future returned by `<[coroutine-closure] as AsyncFnOnce>::call_once` will
98                // drop the coroutine-closure's upvars.
99                let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() {
100                    coroutine_body.coroutine_drop().unwrap()
101                } else {
102                    match (&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!(
103                        args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
104                        ty::ClosureKind::FnOnce
105                    );
106                    tcx.optimized_mir(tcx.coroutine_by_move_body_def_id(coroutine_def_id))
107                        .coroutine_drop()
108                        .unwrap()
109                };
110
111                let mut body =
112                    EarlyBinder::bind(body.clone()).instantiate(tcx, args).skip_norm_wip();
113                {
    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.rs:113",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(113u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = {1:?}",
                                                    instance, body) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = {:?}", instance, body);
114
115                pm::run_passes(
116                    tcx,
117                    &mut body,
118                    &[
119                        &mentioned_items::MentionedItems,
120                        &abort_unwinding_calls::AbortUnwindingCalls,
121                        &add_call_guards::CriticalCallEdges,
122                    ],
123                    Some(MirPhase::Runtime(RuntimePhase::Optimized)),
124                    pm::Optimizations::Allowed,
125                );
126
127                return body;
128            }
129
130            build_drop_shim(tcx, def_id, ty, ty::TypingEnv::post_analysis(tcx, def_id))
131        }
132        ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
133        ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
134        ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
135        ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty) => {
136            let mut body =
137                async_destructor_ctor::build_future_drop_poll_shim(tcx, def_id, proxy_ty, impl_ty);
138
139            pm::run_passes(
140                tcx,
141                &mut body,
142                &[
143                    &mentioned_items::MentionedItems,
144                    &abort_unwinding_calls::AbortUnwindingCalls,
145                    &add_call_guards::CriticalCallEdges,
146                ],
147                Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
148                pm::Optimizations::Allowed,
149            );
150            run_optimization_passes(tcx, &mut body);
151            {
    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.rs:151",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(151u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = {1:?}",
                                                    instance, body) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = {:?}", instance, body);
152            return body;
153        }
154        ty::InstanceKind::AsyncDropGlue(def_id, ty) => {
155            let mut body = async_destructor_ctor::build_async_drop_shim(tcx, def_id, ty);
156
157            // Main pass required here is StateTransform to convert sync drop ladder
158            // into coroutine.
159            // Others are minimal passes as for sync drop glue shim
160            pm::run_passes_no_validate(
161                tcx,
162                &mut body,
163                &[
164                    &mentioned_items::MentionedItems,
165                    &abort_unwinding_calls::AbortUnwindingCalls,
166                    &add_call_guards::CriticalCallEdges,
167                    &simplify::SimplifyCfg::MakeShim,
168                    &crate::coroutine::StateTransform,
169                ],
170                Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
171            );
172            run_optimization_passes(tcx, &mut body);
173            {
    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.rs:173",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(173u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = {1:?}",
                                                    instance, body) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = {:?}", instance, body);
174            return body;
175        }
176
177        ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => {
178            let body = async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty);
179            {
    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.rs:179",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(179u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = {1:?}",
                                                    instance, body) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = {:?}", instance, body);
180            return body;
181        }
182        ty::InstanceKind::Virtual(..) => {
183            ::rustc_middle::util::bug::bug_fmt(format_args!("InstanceKind::Virtual ({0:?}) is for direct calls only",
        instance))bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance)
184        }
185        ty::InstanceKind::Intrinsic(_) => {
186            ::rustc_middle::util::bug::bug_fmt(format_args!("creating shims from intrinsics ({0:?}) is unsupported",
        instance))bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
187        }
188    };
189    {
    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.rs:189",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(189u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = untransformed {1:?}",
                                                    instance, result) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = untransformed {:?}", instance, result);
190
191    deref_finder(tcx, &mut result, false);
192
193    // We don't validate MIR here because the shims may generate code that's
194    // only valid in a `PostAnalysis` param-env. However, since we do initial
195    // validation with the MirBuilt phase, which uses a user-facing param-env.
196    // This causes validation errors when TAITs are involved.
197    pm::run_passes_no_validate(
198        tcx,
199        &mut result,
200        &[
201            &mentioned_items::MentionedItems,
202            &add_moves_for_packed_drops::AddMovesForPackedDrops,
203            &remove_noop_landing_pads::RemoveNoopLandingPads,
204            &simplify::SimplifyCfg::MakeShim,
205            &instsimplify::InstSimplify::BeforeInline,
206            // Perform inlining of `#[rustc_force_inline]`-annotated callees.
207            &inline::ForceInline,
208            &abort_unwinding_calls::AbortUnwindingCalls,
209            &add_call_guards::CriticalCallEdges,
210        ],
211        Some(MirPhase::Runtime(RuntimePhase::Optimized)),
212    );
213
214    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/shim.rs:214",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(214u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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!("make_shim({0:?}) = {1:?}",
                                                    instance, result) as &dyn Value))])
            });
    } else { ; }
};debug!("make_shim({:?}) = {:?}", instance, result);
215
216    result
217}
218
219#[derive(#[automatically_derived]
impl ::core::marker::Copy for DerefSource { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DerefSource {
    #[inline]
    fn clone(&self) -> DerefSource { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for DerefSource {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                DerefSource::ImmRef => "ImmRef",
                DerefSource::MutRef => "MutRef",
                DerefSource::MutPtr => "MutPtr",
            })
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for DerefSource {
    #[inline]
    fn eq(&self, other: &DerefSource) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
220enum DerefSource {
221    /// `fn shim(&self) { inner(*self )}`.
222    ImmRef,
223    /// `fn shim(&mut self) { inner(*self )}`.
224    MutRef,
225    /// `fn shim(*mut self) { inner(*self )}`.
226    MutPtr,
227}
228
229#[derive(#[automatically_derived]
impl ::core::marker::Copy for Adjustment { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Adjustment {
    #[inline]
    fn clone(&self) -> Adjustment {
        let _: ::core::clone::AssertParamIsClone<DerefSource>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Adjustment {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Adjustment::Identity =>
                ::core::fmt::Formatter::write_str(f, "Identity"),
            Adjustment::Deref { source: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Deref",
                    "source", &__self_0),
            Adjustment::RefMut =>
                ::core::fmt::Formatter::write_str(f, "RefMut"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Adjustment {
    #[inline]
    fn eq(&self, other: &Adjustment) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Adjustment::Deref { source: __self_0 }, Adjustment::Deref {
                    source: __arg1_0 }) => __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq)]
230enum Adjustment {
231    /// Pass the receiver as-is.
232    Identity,
233
234    /// We get passed a reference or a raw pointer to `self` and call the target with `*self`.
235    ///
236    /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
237    /// (for `VTableShim`, which effectively is passed `&own Self`).
238    Deref { source: DerefSource },
239
240    /// We get passed `self: Self` and call the target with `&mut self`.
241    ///
242    /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
243    /// won't do it for us.
244    RefMut,
245}
246
247#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for CallKind<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for CallKind<'tcx> {
    #[inline]
    fn clone(&self) -> CallKind<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<DefId>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for CallKind<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CallKind::Indirect(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Indirect", &__self_0),
            CallKind::Direct(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Direct",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for CallKind<'tcx> {
    #[inline]
    fn eq(&self, other: &CallKind<'tcx>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (CallKind::Indirect(__self_0), CallKind::Indirect(__arg1_0))
                    => __self_0 == __arg1_0,
                (CallKind::Direct(__self_0), CallKind::Direct(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq)]
248enum CallKind<'tcx> {
249    /// Call the `FnPtr` that was passed as the receiver.
250    Indirect(Ty<'tcx>),
251
252    /// Call a known `FnDef`.
253    Direct(DefId),
254}
255
256fn local_decls_for_sig<'tcx>(
257    sig: &ty::FnSig<'tcx>,
258    span: Span,
259) -> IndexVec<Local, LocalDecl<'tcx>> {
260    iter::once(LocalDecl::new(sig.output(), span))
261        .chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable()))
262        .collect()
263}
264
265/// Builds the drop glue for the provided type. The `def_id` is that of `core::ptr::drop_glue`.
266///
267/// Inside rustc this is only called on a monomorphic type, but we expose the function for
268/// rustc_driver writers to be able to generate drop glue for a polymorphic type.
269pub fn build_drop_shim<'tcx>(
270    tcx: TyCtxt<'tcx>,
271    def_id: DefId,
272    ty: Option<Ty<'tcx>>,
273    typing_env: ty::TypingEnv<'tcx>,
274) -> Body<'tcx> {
275    {
    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.rs:275",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(275u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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_drop_shim(def_id={0:?}, ty={1:?})",
                                                    def_id, ty) as &dyn Value))])
            });
    } else { ; }
};debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
276
277    if !!#[allow(non_exhaustive_omitted_patterns)] match ty {
                Some(ty) if ty.is_coroutine() => true,
                _ => false,
            } {
    ::core::panicking::panic("assertion failed: !matches!(ty, Some(ty) if ty.is_coroutine())")
};assert!(!matches!(ty, Some(ty) if ty.is_coroutine()));
278
279    let args = if let Some(ty) = ty {
280        tcx.mk_args(&[ty.into()])
281    } else {
282        GenericArgs::identity_for_item(tcx, def_id)
283    };
284    let sig = tcx.fn_sig(def_id).instantiate(tcx, args).skip_norm_wip();
285    let sig = tcx.instantiate_bound_regions_with_erased(sig);
286    let span = tcx.def_span(def_id);
287
288    let source_info = SourceInfo::outermost(span);
289
290    let return_block = BasicBlock::new(1);
291    let mut blocks = IndexVec::with_capacity(2);
292    let block = |blocks: &mut IndexVec<_, _>, kind| {
293        blocks.push(BasicBlockData::new(
294            Some(Terminator { source_info, kind, attributes: ThinVec::new() }),
295            false,
296        ))
297    };
298    if ty.is_some() {
299        block(&mut blocks, TerminatorKind::Goto { target: return_block });
300    }
301    block(&mut blocks, TerminatorKind::Return);
302
303    let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty));
304    let mut body =
305        new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
306
307    let Some(ty) = ty else {
308        return body;
309    };
310
311    let dropee_ptr = Place::from(Local::arg(0));
312
313    if let ty::Array(ety, _len) = *ty.kind() {
314        // Don't write out the elaboration for each array type.
315        // Instead, just delegate to the slice version.
316        let slice_ty = Ty::new_slice(tcx, ety);
317        let mut_slice_ty = Ty::new_ref(tcx, tcx.lifetimes.re_erased, slice_ty, ty::Mutability::Mut);
318        let erased_local = body.local_decls.push(LocalDecl::new(mut_slice_ty, span));
319
320        let start = &mut body.basic_blocks_mut()[START_BLOCK];
321        start.statements.push(Statement::new(
322            source_info,
323            StatementKind::Assign(Box::new((
324                Place::from(erased_local),
325                Rvalue::Cast(
326                    CastKind::PointerCoercion(
327                        ty::adjustment::PointerCoercion::Unsize,
328                        CoercionSource::Implicit,
329                    ),
330                    Operand::Move(dropee_ptr),
331                    mut_slice_ty,
332                ),
333            ))),
334        ));
335        start.terminator = Some(Terminator {
336            source_info,
337            kind: TerminatorKind::Call {
338                func: Operand::function_handle(tcx, def_id, [ty::GenericArg::from(slice_ty)], span),
339                args: Box::new([Spanned { span, node: Operand::Move(Place::from(erased_local)) }]),
340                destination: Place::from(RETURN_PLACE),
341                target: Some(return_block),
342                unwind: UnwindAction::Continue,
343                call_source: CallSource::Misc,
344                fn_span: span,
345            },
346            attributes: ThinVec::new(),
347        });
348    } else {
349        let patch = {
350            let mut elaborator = DropShimElaborator {
351                body: &body,
352                patch: MirPatch::new(&body),
353                tcx,
354                typing_env,
355                produce_async_drops: false,
356            };
357            let dropee = tcx.mk_place_deref(dropee_ptr);
358            let resume_block = elaborator.patch.resume_block();
359            elaborate_drop(
360                &mut elaborator,
361                source_info,
362                dropee,
363                (),
364                return_block,
365                Unwind::To(resume_block),
366                START_BLOCK,
367                None,
368            );
369            elaborator.patch
370        };
371        patch.apply(&mut body);
372    }
373
374    body
375}
376
377fn new_body<'tcx>(
378    source: MirSource<'tcx>,
379    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
380    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
381    arg_count: usize,
382    span: Span,
383) -> Body<'tcx> {
384    let mut body = Body::new(
385        source,
386        basic_blocks,
387        IndexVec::from_elem_n(
388            SourceScopeData {
389                span,
390                parent_scope: None,
391                inlined: None,
392                inlined_parent_scope: None,
393                local_data: ClearCrossCrate::Clear,
394            },
395            1,
396        ),
397        local_decls,
398        IndexVec::new(),
399        arg_count,
400        ::alloc::vec::Vec::new()vec![],
401        span,
402        None,
403        // FIXME(compiler-errors): is this correct?
404        None,
405    );
406    // Shims do not directly mention any consts.
407    body.set_required_consts(Vec::new());
408    body
409}
410
411pub(super) struct DropShimElaborator<'a, 'tcx> {
412    pub body: &'a Body<'tcx>,
413    pub patch: MirPatch<'tcx>,
414    pub tcx: TyCtxt<'tcx>,
415    pub typing_env: ty::TypingEnv<'tcx>,
416    pub produce_async_drops: bool,
417}
418
419impl fmt::Debug for DropShimElaborator<'_, '_> {
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
421        f.debug_struct("DropShimElaborator").finish_non_exhaustive()
422    }
423}
424
425impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
426    type Path = ();
427
428    fn patch_ref(&self) -> &MirPatch<'tcx> {
429        &self.patch
430    }
431    fn patch(&mut self) -> &mut MirPatch<'tcx> {
432        &mut self.patch
433    }
434    fn body(&self) -> &'a Body<'tcx> {
435        self.body
436    }
437    fn tcx(&self) -> TyCtxt<'tcx> {
438        self.tcx
439    }
440    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
441        self.typing_env
442    }
443
444    fn allow_async_drops(&self) -> bool {
445        self.produce_async_drops
446    }
447
448    fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
449        match mode {
450            DropFlagMode::Shallow => {
451                // Drops for the contained fields are "shallow" and "static" - they will simply call
452                // the field's own drop glue.
453                DropStyle::Static
454            }
455            DropFlagMode::Deep => {
456                // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
457                // dropping each field contained in the value.
458                DropStyle::Open
459            }
460        }
461    }
462
463    fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
464        None
465    }
466
467    fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {}
468
469    fn field_subpath(&self, _path: Self::Path, _field: FieldIdx) -> Option<Self::Path> {
470        None
471    }
472    fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
473        None
474    }
475    fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
476        Some(())
477    }
478    fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
479        None
480    }
481}
482
483fn build_thread_local_shim<'tcx>(
484    tcx: TyCtxt<'tcx>,
485    instance: ty::InstanceKind<'tcx>,
486) -> Body<'tcx> {
487    let def_id = instance.def_id();
488
489    let span = tcx.def_span(def_id);
490    let source_info = SourceInfo::outermost(span);
491
492    let blocks = IndexVec::from_raw(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [BasicBlockData::new_stmts(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                            [Statement::new(source_info,
                                        StatementKind::Assign(Box::new((Place::return_place(),
                                                    Rvalue::ThreadLocalRef(def_id)))))])),
                    Some(Terminator {
                            source_info,
                            kind: TerminatorKind::Return,
                            attributes: ThinVec::new(),
                        }), false)]))vec![BasicBlockData::new_stmts(
493        vec![Statement::new(
494            source_info,
495            StatementKind::Assign(Box::new((
496                Place::return_place(),
497                Rvalue::ThreadLocalRef(def_id),
498            ))),
499        )],
500        Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
501        false,
502    )]);
503
504    new_body(
505        MirSource::from_instance(instance),
506        blocks,
507        IndexVec::from_raw(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]))vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
508        0,
509        span,
510    )
511}
512
513/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
514fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
515    {
    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.rs:515",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(515u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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_clone_shim(def_id={0:?})",
                                                    def_id) as &dyn Value))])
            });
    } else { ; }
};debug!("build_clone_shim(def_id={:?})", def_id);
516
517    let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
518
519    let dest = Place::return_place();
520    let src = tcx.mk_place_deref(Place::from(Local::arg(0)));
521
522    match self_ty.kind() {
523        ty::FnDef(..) | ty::FnPtr(..) => builder.copy_shim(),
524        ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
525        ty::CoroutineClosure(_, args) => {
526            builder.tuple_like_shim(dest, src, args.as_coroutine_closure().upvar_tys())
527        }
528        ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
529        ty::Coroutine(coroutine_def_id, args) => {
530            match (&tcx.coroutine_movability(*coroutine_def_id),
        &hir::Movability::Movable) {
    (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!(tcx.coroutine_movability(*coroutine_def_id), hir::Movability::Movable);
531            builder.coroutine_shim(dest, src, *coroutine_def_id, args.as_coroutine())
532        }
533        _ => ::rustc_middle::util::bug::bug_fmt(format_args!("clone shim for `{0:?}` which is not `Copy` and is not an aggregate",
        self_ty))bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
534    };
535
536    builder.into_mir()
537}
538
539struct CloneShimBuilder<'tcx> {
540    tcx: TyCtxt<'tcx>,
541    def_id: DefId,
542    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
543    blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
544    span: Span,
545    sig: ty::FnSig<'tcx>,
546}
547
548impl<'tcx> CloneShimBuilder<'tcx> {
549    fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
550        // we must instantiate the self_ty because it's
551        // otherwise going to be TySelf and we can't index
552        // or access fields of a Place of type TySelf.
553        let sig = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).skip_norm_wip();
554        let sig = tcx.instantiate_bound_regions_with_erased(sig);
555        let span = tcx.def_span(def_id);
556
557        CloneShimBuilder {
558            tcx,
559            def_id,
560            local_decls: local_decls_for_sig(&sig, span),
561            blocks: IndexVec::new(),
562            span,
563            sig,
564        }
565    }
566
567    fn into_mir(self) -> Body<'tcx> {
568        let source = MirSource::from_instance(ty::InstanceKind::CloneShim(
569            self.def_id,
570            self.sig.inputs_and_output[0],
571        ));
572        new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
573    }
574
575    fn source_info(&self) -> SourceInfo {
576        SourceInfo::outermost(self.span)
577    }
578
579    fn block(
580        &mut self,
581        statements: Vec<Statement<'tcx>>,
582        kind: TerminatorKind<'tcx>,
583        is_cleanup: bool,
584    ) -> BasicBlock {
585        let source_info = self.source_info();
586        self.blocks.push(BasicBlockData::new_stmts(
587            statements,
588            Some(Terminator { source_info, kind, attributes: ThinVec::new() }),
589            is_cleanup,
590        ))
591    }
592
593    /// Gives the index of an upcoming BasicBlock, with an offset.
594    /// offset=0 will give you the index of the next BasicBlock,
595    /// offset=1 will give the index of the next-to-next block,
596    /// offset=-1 will give you the index of the last-created block
597    fn block_index_offset(&self, offset: usize) -> BasicBlock {
598        BasicBlock::new(self.blocks.len() + offset)
599    }
600
601    fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
602        Statement::new(self.source_info(), kind)
603    }
604
605    fn copy_shim(&mut self) {
606        let rcvr = self.tcx.mk_place_deref(Place::from(Local::arg(0)));
607        let ret_statement = self.make_statement(StatementKind::Assign(Box::new((
608            Place::return_place(),
609            Rvalue::Use(Operand::Copy(rcvr), WithRetag::Yes),
610        ))));
611        self.block(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [ret_statement]))vec![ret_statement], TerminatorKind::Return, false);
612    }
613
614    fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
615        let span = self.span;
616        let mut local = LocalDecl::new(ty, span);
617        if mutability.is_not() {
618            local = local.immutable();
619        }
620        Place::from(self.local_decls.push(local))
621    }
622
623    fn make_clone_call(
624        &mut self,
625        dest: Place<'tcx>,
626        src: Place<'tcx>,
627        ty: Ty<'tcx>,
628        next: BasicBlock,
629        cleanup: BasicBlock,
630    ) {
631        let tcx = self.tcx;
632
633        // `func == Clone::clone(&ty) -> ty`
634        let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
635        let func = Operand::Constant(Box::new(ConstOperand {
636            span: self.span,
637            user_ty: None,
638            const_: Const::zero_sized(func_ty),
639        }));
640
641        let ref_loc =
642            self.make_place(Mutability::Not, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty));
643
644        // `let ref_loc: &ty = &src;`
645        let statement = self.make_statement(StatementKind::Assign(Box::new((
646            ref_loc,
647            Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
648        ))));
649
650        // `let loc = Clone::clone(ref_loc);`
651        self.block(
652            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [statement]))vec![statement],
653            TerminatorKind::Call {
654                func,
655                args: [Spanned { node: Operand::Move(ref_loc), span: DUMMY_SP }].into(),
656                destination: dest,
657                target: Some(next),
658                unwind: UnwindAction::Cleanup(cleanup),
659                call_source: CallSource::Normal,
660                fn_span: self.span,
661            },
662            false,
663        );
664    }
665
666    fn clone_fields<I>(
667        &mut self,
668        dest: Place<'tcx>,
669        src: Place<'tcx>,
670        target: BasicBlock,
671        mut unwind: BasicBlock,
672        tys: I,
673    ) -> BasicBlock
674    where
675        I: IntoIterator<Item = Ty<'tcx>>,
676    {
677        // For an iterator of length n, create 2*n + 1 blocks.
678        for (i, ity) in tys.into_iter().enumerate() {
679            // Each iteration creates two blocks, referred to here as block 2*i and block 2*i + 1.
680            //
681            // Block 2*i attempts to clone the field. If successful it branches to 2*i + 2 (the
682            // next clone block). If unsuccessful it branches to the previous unwind block, which
683            // is initially the `unwind` argument passed to this function.
684            //
685            // Block 2*i + 1 is the unwind block for this iteration. It drops the cloned value
686            // created by block 2*i. We store this block in `unwind` so that the next clone block
687            // will unwind to it if cloning fails.
688
689            let field = FieldIdx::new(i);
690            let src_field = self.tcx.mk_place_field(src, field, ity);
691
692            let dest_field = self.tcx.mk_place_field(dest, field, ity);
693
694            let next_unwind = self.block_index_offset(1);
695            let next_block = self.block_index_offset(2);
696            self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
697            self.block(
698                ::alloc::vec::Vec::new()vec![],
699                TerminatorKind::Drop {
700                    place: dest_field,
701                    target: unwind,
702                    unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
703                    replace: false,
704                    drop: None,
705                },
706                /* is_cleanup */ true,
707            );
708            unwind = next_unwind;
709        }
710        // If all clones succeed then we end up here.
711        self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Goto { target }, false);
712        unwind
713    }
714
715    fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
716    where
717        I: IntoIterator<Item = Ty<'tcx>>,
718    {
719        self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
720        let unwind = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::UnwindResume, true);
721        let target = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Return, false);
722
723        let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys);
724    }
725
726    fn coroutine_shim(
727        &mut self,
728        dest: Place<'tcx>,
729        src: Place<'tcx>,
730        coroutine_def_id: DefId,
731        args: CoroutineArgs<TyCtxt<'tcx>>,
732    ) {
733        self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
734        let unwind = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::UnwindResume, true);
735        // This will get overwritten with a switch once we know the target blocks
736        let switch = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Unreachable, false);
737        let unwind = self.clone_fields(dest, src, switch, unwind, args.upvar_tys());
738        let target = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Return, false);
739        let unreachable = self.block(::alloc::vec::Vec::new()vec![], TerminatorKind::Unreachable, false);
740        let mut cases = Vec::with_capacity(args.state_tys(coroutine_def_id, self.tcx).count());
741        for (index, state_tys) in args.state_tys(coroutine_def_id, self.tcx).enumerate() {
742            let variant_index = VariantIdx::new(index);
743            let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index);
744            let src = self.tcx.mk_place_downcast_unnamed(src, variant_index);
745            let clone_block = self.block_index_offset(1);
746            let start_block = self.block(
747                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.make_statement(StatementKind::SetDiscriminant {
                        place: Box::new(Place::return_place()),
                        variant_index,
                    })]))vec![self.make_statement(StatementKind::SetDiscriminant {
748                    place: Box::new(Place::return_place()),
749                    variant_index,
750                })],
751                TerminatorKind::Goto { target: clone_block },
752                false,
753            );
754            cases.push((index as u128, start_block));
755            let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys);
756        }
757        let discr_ty = args.discr_ty(self.tcx);
758        let temp = self.make_place(Mutability::Mut, discr_ty);
759        let rvalue = Rvalue::Discriminant(src);
760        let statement = self.make_statement(StatementKind::Assign(Box::new((temp, rvalue))));
761        match &mut self.blocks[switch] {
762            BasicBlockData { statements, terminator: Some(Terminator { kind, .. }), .. } => {
763                statements.push(statement);
764                *kind = TerminatorKind::SwitchInt {
765                    discr: Operand::Move(temp),
766                    targets: SwitchTargets::new(cases.into_iter(), unreachable),
767                };
768            }
769            BasicBlockData { terminator: None, .. } => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
770        }
771    }
772}
773
774/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
775/// first adjusting its first argument according to `rcvr_adjustment`.
776x;#[instrument(level = "debug", skip(tcx), ret)]
777fn build_call_shim<'tcx>(
778    tcx: TyCtxt<'tcx>,
779    instance: ty::InstanceKind<'tcx>,
780    rcvr_adjustment: Option<Adjustment>,
781    call_kind: CallKind<'tcx>,
782) -> Body<'tcx> {
783    // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
784    // to instantiate into the signature of the shim. It is not necessary for users of this
785    // MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`).
786    let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance {
787        let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx));
788
789        let untuple_args = sig.inputs();
790
791        // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
792        let arg_tup = Ty::new_tup(tcx, untuple_args);
793
794        (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
795    } else {
796        (None, None)
797    };
798
799    let def_id = instance.def_id();
800
801    let sig = tcx.fn_sig(def_id);
802    let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));
803
804    assert_eq!(sig_args.is_some(), !instance.has_polymorphic_mir_body());
805    let mut sig = if let Some(sig_args) = sig_args {
806        sig.instantiate(tcx, &sig_args).skip_norm_wip()
807    } else {
808        sig.instantiate_identity().skip_norm_wip()
809    };
810
811    if let CallKind::Indirect(fnty) = call_kind {
812        // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
813        // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
814        // the implemented `FnX` trait.
815
816        // Apply the opposite adjustment to the MIR input.
817        let mut inputs_and_output = sig.inputs_and_output.to_vec();
818
819        // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
820        // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
821        assert_eq!(inputs_and_output.len(), 3);
822
823        // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
824        // `FnDef` and `FnPtr` callees, not the `Self` type param.
825        let self_arg = &mut inputs_and_output[0];
826        *self_arg = match rcvr_adjustment.unwrap() {
827            Adjustment::Identity => fnty,
828            Adjustment::Deref { source } => match source {
829                DerefSource::ImmRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fnty),
830                DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty),
831                DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty),
832            },
833            Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"),
834        };
835        sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
836    }
837
838    // FIXME: Avoid having to adjust the signature both here and in
839    // `fn_sig_for_fn_abi`.
840    if let ty::InstanceKind::VTableShim(..) = instance {
841        // Modify fn(self, ...) to fn(self: *mut Self, ...)
842        let mut inputs_and_output = sig.inputs_and_output.to_vec();
843        let self_arg = &mut inputs_and_output[0];
844        debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
845        *self_arg = Ty::new_mut_ptr(tcx, *self_arg);
846        sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
847    }
848
849    let span = tcx.def_span(def_id);
850
851    debug!(?sig);
852
853    let mut local_decls = local_decls_for_sig(&sig, span);
854    let source_info = SourceInfo::outermost(span);
855
856    let destination = Place::return_place();
857
858    let rcvr_place = || {
859        assert!(rcvr_adjustment.is_some());
860        Place::from(Local::arg(0))
861    };
862    let mut statements = vec![];
863
864    let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
865        Adjustment::Identity => Operand::Move(rcvr_place()),
866        Adjustment::Deref { source: _ } => Operand::Move(tcx.mk_place_deref(rcvr_place())),
867        Adjustment::RefMut => {
868            // let rcvr = &mut rcvr;
869            let ref_rcvr = local_decls.push(
870                LocalDecl::new(
871                    Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, sig.inputs()[0]),
872                    span,
873                )
874                .immutable(),
875            );
876            let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default };
877            statements.push(Statement::new(
878                source_info,
879                StatementKind::Assign(Box::new((
880                    Place::from(ref_rcvr),
881                    Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
882                ))),
883            ));
884            Operand::Move(Place::from(ref_rcvr))
885        }
886    });
887
888    let (callee, mut args) = match call_kind {
889        // `FnPtr` call has no receiver. Args are untupled below.
890        CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
891
892        // `FnDef` call with optional receiver.
893        CallKind::Direct(def_id) => {
894            let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
895            (
896                Operand::Constant(Box::new(ConstOperand {
897                    span,
898                    user_ty: None,
899                    const_: Const::zero_sized(ty),
900                })),
901                rcvr.into_iter().collect::<Vec<_>>(),
902            )
903        }
904    };
905
906    let mut arg_range = 0..sig.inputs().len();
907
908    // Take the `self` ("receiver") argument out of the range (it's adjusted above).
909    if rcvr_adjustment.is_some() {
910        arg_range.start += 1;
911    }
912
913    // Take the last argument, if we need to untuple it (handled below).
914    if untuple_args.is_some() {
915        arg_range.end -= 1;
916    }
917
918    // Pass all of the non-special arguments directly.
919    args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::arg(i)))));
920
921    // Untuple the last argument, if we have to.
922    if let Some(untuple_args) = untuple_args {
923        let tuple_arg = Local::arg(sig.inputs().len() - 1);
924        args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
925            Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), FieldIdx::new(i), *ity))
926        }));
927    }
928
929    let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
930    let mut blocks = IndexVec::with_capacity(n_blocks);
931    let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
932        blocks.push(BasicBlockData::new_stmts(
933            statements,
934            Some(Terminator { source_info, kind, attributes: ThinVec::new() }),
935            is_cleanup,
936        ))
937    };
938
939    // BB #0
940    let args = args.into_iter().map(|a| Spanned { node: a, span: DUMMY_SP }).collect();
941    block(
942        &mut blocks,
943        statements,
944        TerminatorKind::Call {
945            func: callee,
946            args,
947            destination,
948            target: Some(BasicBlock::new(1)),
949            unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
950                UnwindAction::Cleanup(BasicBlock::new(3))
951            } else {
952                UnwindAction::Continue
953            },
954            call_source: CallSource::Misc,
955            fn_span: span,
956        },
957        false,
958    );
959
960    if let Some(Adjustment::RefMut) = rcvr_adjustment {
961        // BB #1 - drop for Self
962        block(
963            &mut blocks,
964            vec![],
965            TerminatorKind::Drop {
966                place: rcvr_place(),
967                target: BasicBlock::new(2),
968                unwind: UnwindAction::Continue,
969                replace: false,
970                drop: None,
971            },
972            false,
973        );
974    }
975    // BB #1/#2 - return
976    let stmts = vec![];
977    block(&mut blocks, stmts, TerminatorKind::Return, false);
978    if let Some(Adjustment::RefMut) = rcvr_adjustment {
979        // BB #3 - drop if closure panics
980        block(
981            &mut blocks,
982            vec![],
983            TerminatorKind::Drop {
984                place: rcvr_place(),
985                target: BasicBlock::new(4),
986                unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
987                replace: false,
988                drop: None,
989            },
990            /* is_cleanup */ true,
991        );
992
993        // BB #4 - resume
994        block(&mut blocks, vec![], TerminatorKind::UnwindResume, true);
995    }
996
997    let mut body =
998        new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
999
1000    if let ExternAbi::RustCall = sig.abi() {
1001        body.spread_arg = Some(Local::new(sig.inputs().len()));
1002    }
1003
1004    body
1005}
1006
1007pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
1008    if true {
    if !tcx.is_constructor(ctor_id) {
        ::core::panicking::panic("assertion failed: tcx.is_constructor(ctor_id)")
    };
};debug_assert!(tcx.is_constructor(ctor_id));
1009
1010    let typing_env = ty::TypingEnv::post_analysis(tcx, ctor_id);
1011
1012    // Normalize the sig.
1013    let sig = tcx
1014        .fn_sig(ctor_id)
1015        .instantiate_identity()
1016        .skip_norm_wip()
1017        .no_bound_vars()
1018        .expect("LBR in ADT constructor signature");
1019    let sig = tcx.normalize_erasing_regions(typing_env, Unnormalized::new_wip(sig));
1020
1021    let ty::Adt(adt_def, args) = sig.output().kind() else {
1022        ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected type for ADT ctor {0:?}",
        sig.output()));bug!("unexpected type for ADT ctor {:?}", sig.output());
1023    };
1024
1025    {
    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.rs:1025",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(1025u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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_ctor: ctor_id={0:?} sig={1:?}",
                                                    ctor_id, sig) as &dyn Value))])
            });
    } else { ; }
};debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
1026
1027    let span = tcx.def_span(ctor_id);
1028
1029    let local_decls = local_decls_for_sig(&sig, span);
1030
1031    let source_info = SourceInfo::outermost(span);
1032
1033    let variant_index =
1034        if adt_def.is_enum() { adt_def.variant_index_with_ctor_id(ctor_id) } else { FIRST_VARIANT };
1035
1036    // Generate the following MIR:
1037    //
1038    // (return as Variant).field0 = arg0;
1039    // (return as Variant).field1 = arg1;
1040    //
1041    // return;
1042    {
    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.rs:1042",
                        "rustc_mir_transform::shim", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/shim.rs"),
                        ::tracing_core::__macro_support::Option::Some(1042u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_transform::shim"),
                        ::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_ctor: variant_index={0:?}",
                                                    variant_index) as &dyn Value))])
            });
    } else { ; }
};debug!("build_ctor: variant_index={:?}", variant_index);
1043
1044    let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None);
1045    let variant = adt_def.variant(variant_index);
1046    let statement = Statement::new(
1047        source_info,
1048        StatementKind::Assign(Box::new((
1049            Place::return_place(),
1050            Rvalue::Aggregate(
1051                Box::new(kind),
1052                (0..variant.fields.len())
1053                    .map(|idx| Operand::Move(Place::from(Local::arg(idx))))
1054                    .collect(),
1055            ),
1056        ))),
1057    );
1058
1059    let start_block = BasicBlockData::new_stmts(
1060        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [statement]))vec![statement],
1061        Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
1062        false,
1063    );
1064
1065    let source = MirSource::item(ctor_id);
1066    let mut body = new_body(
1067        source,
1068        IndexVec::from_elem_n(start_block, 1),
1069        local_decls,
1070        sig.inputs().len(),
1071        span,
1072    );
1073    // A constructor doesn't mention any other items (and we don't run the usual optimization passes
1074    // so this would otherwise not get filled).
1075    body.set_mentioned_items(Vec::new());
1076
1077    crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
1078
1079    body
1080}
1081
1082/// ```ignore (pseudo-impl)
1083/// impl FnPtr for fn(u32) {
1084///     fn addr(self) -> usize {
1085///         self as usize
1086///     }
1087/// }
1088/// ```
1089fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
1090    {
    match self_ty.kind() {
        ty::FnPtr(..) => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "ty::FnPtr(..)",
                ::core::option::Option::Some(format_args!("expected fn ptr, found {0}",
                        self_ty)));
        }
    }
};assert_matches!(self_ty.kind(), ty::FnPtr(..), "expected fn ptr, found {self_ty}");
1091    let span = tcx.def_span(def_id);
1092    let Some(sig) =
1093        tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).skip_norm_wip().no_bound_vars()
1094    else {
1095        ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("FnPtr::addr with bound vars for `{0}`", self_ty));span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
1096    };
1097    let locals = local_decls_for_sig(&sig, span);
1098
1099    let source_info = SourceInfo::outermost(span);
1100    // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful
1101    // provenance.
1102    let rvalue = Rvalue::Cast(
1103        CastKind::FnPtrToPtr,
1104        Operand::Move(Place::from(Local::arg(0))),
1105        Ty::new_imm_ptr(tcx, tcx.types.unit),
1106    );
1107    let stmt = Statement::new(
1108        source_info,
1109        StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
1110    );
1111    let statements = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt];
1112    let start_block = BasicBlockData::new_stmts(
1113        statements,
1114        Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
1115        false,
1116    );
1117    let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty));
1118    new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
1119}
1120
1121fn build_construct_coroutine_by_move_shim<'tcx>(
1122    tcx: TyCtxt<'tcx>,
1123    coroutine_closure_def_id: DefId,
1124    receiver_by_ref: bool,
1125) -> Body<'tcx> {
1126    let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity().skip_norm_wip();
1127    let mut self_local: Place<'tcx> = Local::arg(0).into();
1128    let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
1129        ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
1130    };
1131
1132    // We use `&Self` here because we only need to emit an ABI-compatible shim body,
1133    // rather than match the signature exactly (which might take `&mut self` instead).
1134    //
1135    // We adjust the `self_local` to be a deref since we want to copy fields out of
1136    // a reference to the closure.
1137    if receiver_by_ref {
1138        self_local = tcx.mk_place_deref(self_local);
1139        self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty);
1140    }
1141
1142    let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
1143        tcx.mk_fn_sig(
1144            [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()),
1145            sig.to_coroutine_given_kind_and_upvars(
1146                tcx,
1147                args.as_coroutine_closure().parent_args(),
1148                tcx.coroutine_for_closure(coroutine_closure_def_id),
1149                ty::ClosureKind::FnOnce,
1150                tcx.lifetimes.re_erased,
1151                args.as_coroutine_closure().tupled_upvars_ty(),
1152                args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
1153            ),
1154            sig.fn_sig_kind,
1155        )
1156    });
1157    let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig);
1158    let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else {
1159        ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
1160    };
1161
1162    let span = tcx.def_span(coroutine_closure_def_id);
1163    let locals = local_decls_for_sig(&sig, span);
1164
1165    let mut fields = ::alloc::vec::Vec::new()vec![];
1166
1167    // Move all of the closure args.
1168    for idx in 1..sig.inputs().len() {
1169        fields.push(Operand::Move(Local::arg(idx).into()));
1170    }
1171
1172    for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
1173        if receiver_by_ref {
1174            // The only situation where it's possible is when we capture immuatable references,
1175            // since those don't need to be reborrowed with the closure's env lifetime. Since
1176            // references are always `Copy`, just emit a copy.
1177            if !#[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Ref(_, _, hir::Mutability::Not) => true,
    _ => false,
}matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) {
1178                // This copy is only sound if it's a `&T`. This may be
1179                // reachable e.g. when eagerly computing the `Fn` instance
1180                // of an async closure that doesn't borrowck.
1181                tcx.dcx().delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("field should be captured by immutable ref if we have an `Fn` instance, but it was: {0}",
                ty))
    })format!(
1182                    "field should be captured by immutable ref if we have \
1183                    an `Fn` instance, but it was: {ty}"
1184                ));
1185            }
1186            fields.push(Operand::Copy(tcx.mk_place_field(
1187                self_local,
1188                FieldIdx::from_usize(idx),
1189                ty,
1190            )));
1191        } else {
1192            fields.push(Operand::Move(tcx.mk_place_field(
1193                self_local,
1194                FieldIdx::from_usize(idx),
1195                ty,
1196            )));
1197        }
1198    }
1199
1200    let source_info = SourceInfo::outermost(span);
1201    let rvalue = Rvalue::Aggregate(
1202        Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
1203        IndexVec::from_raw(fields),
1204    );
1205    let stmt = Statement::new(
1206        source_info,
1207        StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
1208    );
1209    let statements = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [stmt]))vec![stmt];
1210    let start_block = BasicBlockData::new_stmts(
1211        statements,
1212        Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }),
1213        false,
1214    );
1215
1216    let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim {
1217        coroutine_closure_def_id,
1218        receiver_by_ref,
1219    });
1220
1221    let body =
1222        new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span);
1223
1224    let pass_name =
1225        if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" };
1226    if let Some(dumper) = MirDumper::new(tcx, pass_name, &body) {
1227        dumper.dump_mir(&body);
1228    }
1229
1230    body
1231}