rustc_mir_transform/
shim.rs

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