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::*;
10use rustc_middle::query::Providers;
11use rustc_middle::ty::{
12 self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
13};
14use rustc_middle::{bug, span_bug};
15use rustc_span::source_map::Spanned;
16use rustc_span::{DUMMY_SP, Span};
17use tracing::{debug, instrument};
18
19use crate::elaborate_drop::{DropElaborator, DropFlagMode, DropStyle, Unwind, elaborate_drop};
20use crate::patch::MirPatch;
21use crate::{
22 abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, inline,
23 instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
24};
25
26mod async_destructor_ctor;
27
28pub(super) fn provide(providers: &mut Providers) {
29 providers.mir_shims = make_shim;
30}
31
32fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> {
33 debug!("make_shim({:?})", instance);
34
35 let mut result = match instance {
36 ty::InstanceKind::Item(..) => bug!("item {:?} passed to make_shim", instance),
37 ty::InstanceKind::VTableShim(def_id) => {
38 let adjustment = Adjustment::Deref { source: DerefSource::MutPtr };
39 build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
40 }
41 ty::InstanceKind::FnPtrShim(def_id, ty) => {
42 let trait_ = tcx.trait_of_item(def_id).unwrap();
43 let adjustment = match tcx
45 .fn_trait_kind_from_def_id(trait_)
46 .or_else(|| tcx.async_fn_trait_kind_from_def_id(trait_))
47 {
48 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
49 Some(ty::ClosureKind::Fn) => Adjustment::Deref { source: DerefSource::ImmRef },
50 Some(ty::ClosureKind::FnMut) => Adjustment::Deref { source: DerefSource::MutRef },
51 None => bug!("fn pointer {:?} is not an fn", ty),
52 };
53
54 build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
55 }
56 ty::InstanceKind::ReifyShim(def_id, _) => {
62 build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
63 }
64 ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => {
65 let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
66 let call_mut = tcx
67 .associated_items(fn_mut)
68 .in_definition_order()
69 .find(|it| it.kind == ty::AssocKind::Fn)
70 .unwrap()
71 .def_id;
72
73 build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
74 }
75
76 ty::InstanceKind::ConstructCoroutineInClosureShim {
77 coroutine_closure_def_id,
78 receiver_by_ref,
79 } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref),
80
81 ty::InstanceKind::DropGlue(def_id, ty) => {
82 if let Some(&ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) {
85 let coroutine_body = tcx.optimized_mir(coroutine_def_id);
86
87 let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
88 else {
89 bug!()
90 };
91
92 let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() {
98 coroutine_body.coroutine_drop().unwrap()
99 } else {
100 assert_eq!(
101 args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
102 ty::ClosureKind::FnOnce
103 );
104 tcx.optimized_mir(tcx.coroutine_by_move_body_def_id(coroutine_def_id))
105 .coroutine_drop()
106 .unwrap()
107 };
108
109 let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args);
110 debug!("make_shim({:?}) = {:?}", instance, body);
111
112 pm::run_passes(
113 tcx,
114 &mut body,
115 &[
116 &mentioned_items::MentionedItems,
117 &abort_unwinding_calls::AbortUnwindingCalls,
118 &add_call_guards::CriticalCallEdges,
119 ],
120 Some(MirPhase::Runtime(RuntimePhase::Optimized)),
121 pm::Optimizations::Allowed,
122 );
123
124 return body;
125 }
126
127 build_drop_shim(tcx, def_id, ty)
128 }
129 ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
130 ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
131 ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
132 ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => {
133 async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty)
134 }
135 ty::InstanceKind::Virtual(..) => {
136 bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance)
137 }
138 ty::InstanceKind::Intrinsic(_) => {
139 bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
140 }
141 };
142 debug!("make_shim({:?}) = untransformed {:?}", instance, result);
143
144 pm::run_passes_no_validate(
149 tcx,
150 &mut result,
151 &[
152 &mentioned_items::MentionedItems,
153 &add_moves_for_packed_drops::AddMovesForPackedDrops,
154 &deref_separator::Derefer,
155 &remove_noop_landing_pads::RemoveNoopLandingPads,
156 &simplify::SimplifyCfg::MakeShim,
157 &instsimplify::InstSimplify::BeforeInline,
158 &inline::ForceInline,
160 &abort_unwinding_calls::AbortUnwindingCalls,
161 &add_call_guards::CriticalCallEdges,
162 ],
163 Some(MirPhase::Runtime(RuntimePhase::Optimized)),
164 );
165
166 debug!("make_shim({:?}) = {:?}", instance, result);
167
168 result
169}
170
171#[derive(Copy, Clone, Debug, PartialEq)]
172enum DerefSource {
173 ImmRef,
175 MutRef,
177 MutPtr,
179}
180
181#[derive(Copy, Clone, Debug, PartialEq)]
182enum Adjustment {
183 Identity,
185
186 Deref { source: DerefSource },
191
192 RefMut,
197}
198
199#[derive(Copy, Clone, Debug, PartialEq)]
200enum CallKind<'tcx> {
201 Indirect(Ty<'tcx>),
203
204 Direct(DefId),
206}
207
208fn local_decls_for_sig<'tcx>(
209 sig: &ty::FnSig<'tcx>,
210 span: Span,
211) -> IndexVec<Local, LocalDecl<'tcx>> {
212 iter::once(LocalDecl::new(sig.output(), span))
213 .chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable()))
214 .collect()
215}
216
217fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
218 debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
219
220 assert!(!matches!(ty, Some(ty) if ty.is_coroutine()));
221
222 let args = if let Some(ty) = ty {
223 tcx.mk_args(&[ty.into()])
224 } else {
225 GenericArgs::identity_for_item(tcx, def_id)
226 };
227 let sig = tcx.fn_sig(def_id).instantiate(tcx, args);
228 let sig = tcx.instantiate_bound_regions_with_erased(sig);
229 let span = tcx.def_span(def_id);
230
231 let source_info = SourceInfo::outermost(span);
232
233 let return_block = BasicBlock::new(1);
234 let mut blocks = IndexVec::with_capacity(2);
235 let block = |blocks: &mut IndexVec<_, _>, kind| {
236 blocks.push(BasicBlockData {
237 statements: vec![],
238 terminator: Some(Terminator { source_info, kind }),
239 is_cleanup: false,
240 })
241 };
242 block(&mut blocks, TerminatorKind::Goto { target: return_block });
243 block(&mut blocks, TerminatorKind::Return);
244
245 let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty));
246 let mut body =
247 new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
248
249 let mut dropee_ptr = Place::from(Local::new(1 + 0));
251 if tcx.sess.opts.unstable_opts.mir_emit_retag {
252 let reborrow = Rvalue::Ref(
261 tcx.lifetimes.re_erased,
262 BorrowKind::Mut { kind: MutBorrowKind::Default },
263 tcx.mk_place_deref(dropee_ptr),
264 );
265 let ref_ty = reborrow.ty(body.local_decls(), tcx);
266 dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into();
267 let new_statements = [
268 StatementKind::Assign(Box::new((dropee_ptr, reborrow))),
269 StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
270 ];
271 for s in new_statements {
272 body.basic_blocks_mut()[START_BLOCK]
273 .statements
274 .push(Statement { source_info, kind: s });
275 }
276 }
277
278 if ty.is_some() {
279 let patch = {
280 let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
281 let mut elaborator =
282 DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, typing_env };
283 let dropee = tcx.mk_place_deref(dropee_ptr);
284 let resume_block = elaborator.patch.resume_block();
285 elaborate_drop(
286 &mut elaborator,
287 source_info,
288 dropee,
289 (),
290 return_block,
291 Unwind::To(resume_block),
292 START_BLOCK,
293 );
294 elaborator.patch
295 };
296 patch.apply(&mut body);
297 }
298
299 body
300}
301
302fn new_body<'tcx>(
303 source: MirSource<'tcx>,
304 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
305 local_decls: IndexVec<Local, LocalDecl<'tcx>>,
306 arg_count: usize,
307 span: Span,
308) -> Body<'tcx> {
309 let mut body = Body::new(
310 source,
311 basic_blocks,
312 IndexVec::from_elem_n(
313 SourceScopeData {
314 span,
315 parent_scope: None,
316 inlined: None,
317 inlined_parent_scope: None,
318 local_data: ClearCrossCrate::Clear,
319 },
320 1,
321 ),
322 local_decls,
323 IndexVec::new(),
324 arg_count,
325 vec![],
326 span,
327 None,
328 None,
330 );
331 body.set_required_consts(Vec::new());
333 body
334}
335
336pub(super) struct DropShimElaborator<'a, 'tcx> {
337 pub body: &'a Body<'tcx>,
338 pub patch: MirPatch<'tcx>,
339 pub tcx: TyCtxt<'tcx>,
340 pub typing_env: ty::TypingEnv<'tcx>,
341}
342
343impl fmt::Debug for DropShimElaborator<'_, '_> {
344 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
345 Ok(())
346 }
347}
348
349impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
350 type Path = ();
351
352 fn patch_ref(&self) -> &MirPatch<'tcx> {
353 &self.patch
354 }
355 fn patch(&mut self) -> &mut MirPatch<'tcx> {
356 &mut self.patch
357 }
358 fn body(&self) -> &'a Body<'tcx> {
359 self.body
360 }
361 fn tcx(&self) -> TyCtxt<'tcx> {
362 self.tcx
363 }
364 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
365 self.typing_env
366 }
367
368 fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
369 match mode {
370 DropFlagMode::Shallow => {
371 DropStyle::Static
374 }
375 DropFlagMode::Deep => {
376 DropStyle::Open
379 }
380 }
381 }
382
383 fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
384 None
385 }
386
387 fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {}
388
389 fn field_subpath(&self, _path: Self::Path, _field: FieldIdx) -> Option<Self::Path> {
390 None
391 }
392 fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
393 None
394 }
395 fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
396 Some(())
397 }
398 fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
399 None
400 }
401}
402
403fn build_thread_local_shim<'tcx>(
404 tcx: TyCtxt<'tcx>,
405 instance: ty::InstanceKind<'tcx>,
406) -> Body<'tcx> {
407 let def_id = instance.def_id();
408
409 let span = tcx.def_span(def_id);
410 let source_info = SourceInfo::outermost(span);
411
412 let blocks = IndexVec::from_raw(vec![BasicBlockData {
413 statements: vec![Statement {
414 source_info,
415 kind: StatementKind::Assign(Box::new((
416 Place::return_place(),
417 Rvalue::ThreadLocalRef(def_id),
418 ))),
419 }],
420 terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
421 is_cleanup: false,
422 }]);
423
424 new_body(
425 MirSource::from_instance(instance),
426 blocks,
427 IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
428 0,
429 span,
430 )
431}
432
433fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
435 debug!("build_clone_shim(def_id={:?})", def_id);
436
437 let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
438
439 let dest = Place::return_place();
440 let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
441
442 match self_ty.kind() {
443 ty::FnDef(..) | ty::FnPtr(..) => builder.copy_shim(),
444 ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
445 ty::CoroutineClosure(_, args) => {
446 builder.tuple_like_shim(dest, src, args.as_coroutine_closure().upvar_tys())
447 }
448 ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
449 ty::Coroutine(coroutine_def_id, args) => {
450 assert_eq!(tcx.coroutine_movability(*coroutine_def_id), hir::Movability::Movable);
451 builder.coroutine_shim(dest, src, *coroutine_def_id, args.as_coroutine())
452 }
453 _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
454 };
455
456 builder.into_mir()
457}
458
459struct CloneShimBuilder<'tcx> {
460 tcx: TyCtxt<'tcx>,
461 def_id: DefId,
462 local_decls: IndexVec<Local, LocalDecl<'tcx>>,
463 blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
464 span: Span,
465 sig: ty::FnSig<'tcx>,
466}
467
468impl<'tcx> CloneShimBuilder<'tcx> {
469 fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
470 let sig = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]);
474 let sig = tcx.instantiate_bound_regions_with_erased(sig);
475 let span = tcx.def_span(def_id);
476
477 CloneShimBuilder {
478 tcx,
479 def_id,
480 local_decls: local_decls_for_sig(&sig, span),
481 blocks: IndexVec::new(),
482 span,
483 sig,
484 }
485 }
486
487 fn into_mir(self) -> Body<'tcx> {
488 let source = MirSource::from_instance(ty::InstanceKind::CloneShim(
489 self.def_id,
490 self.sig.inputs_and_output[0],
491 ));
492 new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
493 }
494
495 fn source_info(&self) -> SourceInfo {
496 SourceInfo::outermost(self.span)
497 }
498
499 fn block(
500 &mut self,
501 statements: Vec<Statement<'tcx>>,
502 kind: TerminatorKind<'tcx>,
503 is_cleanup: bool,
504 ) -> BasicBlock {
505 let source_info = self.source_info();
506 self.blocks.push(BasicBlockData {
507 statements,
508 terminator: Some(Terminator { source_info, kind }),
509 is_cleanup,
510 })
511 }
512
513 fn block_index_offset(&self, offset: usize) -> BasicBlock {
518 BasicBlock::new(self.blocks.len() + offset)
519 }
520
521 fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
522 Statement { source_info: self.source_info(), kind }
523 }
524
525 fn copy_shim(&mut self) {
526 let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
527 let ret_statement = self.make_statement(StatementKind::Assign(Box::new((
528 Place::return_place(),
529 Rvalue::Use(Operand::Copy(rcvr)),
530 ))));
531 self.block(vec![ret_statement], TerminatorKind::Return, false);
532 }
533
534 fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
535 let span = self.span;
536 let mut local = LocalDecl::new(ty, span);
537 if mutability.is_not() {
538 local = local.immutable();
539 }
540 Place::from(self.local_decls.push(local))
541 }
542
543 fn make_clone_call(
544 &mut self,
545 dest: Place<'tcx>,
546 src: Place<'tcx>,
547 ty: Ty<'tcx>,
548 next: BasicBlock,
549 cleanup: BasicBlock,
550 ) {
551 let tcx = self.tcx;
552
553 let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
555 let func = Operand::Constant(Box::new(ConstOperand {
556 span: self.span,
557 user_ty: None,
558 const_: Const::zero_sized(func_ty),
559 }));
560
561 let ref_loc =
562 self.make_place(Mutability::Not, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty));
563
564 let statement = self.make_statement(StatementKind::Assign(Box::new((
566 ref_loc,
567 Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
568 ))));
569
570 self.block(
572 vec![statement],
573 TerminatorKind::Call {
574 func,
575 args: [Spanned { node: Operand::Move(ref_loc), span: DUMMY_SP }].into(),
576 destination: dest,
577 target: Some(next),
578 unwind: UnwindAction::Cleanup(cleanup),
579 call_source: CallSource::Normal,
580 fn_span: self.span,
581 },
582 false,
583 );
584 }
585
586 fn clone_fields<I>(
587 &mut self,
588 dest: Place<'tcx>,
589 src: Place<'tcx>,
590 target: BasicBlock,
591 mut unwind: BasicBlock,
592 tys: I,
593 ) -> BasicBlock
594 where
595 I: IntoIterator<Item = Ty<'tcx>>,
596 {
597 for (i, ity) in tys.into_iter().enumerate() {
599 let field = FieldIdx::new(i);
610 let src_field = self.tcx.mk_place_field(src, field, ity);
611
612 let dest_field = self.tcx.mk_place_field(dest, field, ity);
613
614 let next_unwind = self.block_index_offset(1);
615 let next_block = self.block_index_offset(2);
616 self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
617 self.block(
618 vec![],
619 TerminatorKind::Drop {
620 place: dest_field,
621 target: unwind,
622 unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
623 replace: false,
624 },
625 true,
626 );
627 unwind = next_unwind;
628 }
629 self.block(vec![], TerminatorKind::Goto { target }, false);
631 unwind
632 }
633
634 fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
635 where
636 I: IntoIterator<Item = Ty<'tcx>>,
637 {
638 self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
639 let unwind = self.block(vec![], TerminatorKind::UnwindResume, true);
640 let target = self.block(vec![], TerminatorKind::Return, false);
641
642 let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys);
643 }
644
645 fn coroutine_shim(
646 &mut self,
647 dest: Place<'tcx>,
648 src: Place<'tcx>,
649 coroutine_def_id: DefId,
650 args: CoroutineArgs<TyCtxt<'tcx>>,
651 ) {
652 self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
653 let unwind = self.block(vec![], TerminatorKind::UnwindResume, true);
654 let switch = self.block(vec![], TerminatorKind::Unreachable, false);
656 let unwind = self.clone_fields(dest, src, switch, unwind, args.upvar_tys());
657 let target = self.block(vec![], TerminatorKind::Return, false);
658 let unreachable = self.block(vec![], TerminatorKind::Unreachable, false);
659 let mut cases = Vec::with_capacity(args.state_tys(coroutine_def_id, self.tcx).count());
660 for (index, state_tys) in args.state_tys(coroutine_def_id, self.tcx).enumerate() {
661 let variant_index = VariantIdx::new(index);
662 let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index);
663 let src = self.tcx.mk_place_downcast_unnamed(src, variant_index);
664 let clone_block = self.block_index_offset(1);
665 let start_block = self.block(
666 vec![self.make_statement(StatementKind::SetDiscriminant {
667 place: Box::new(Place::return_place()),
668 variant_index,
669 })],
670 TerminatorKind::Goto { target: clone_block },
671 false,
672 );
673 cases.push((index as u128, start_block));
674 let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys);
675 }
676 let discr_ty = args.discr_ty(self.tcx);
677 let temp = self.make_place(Mutability::Mut, discr_ty);
678 let rvalue = Rvalue::Discriminant(src);
679 let statement = self.make_statement(StatementKind::Assign(Box::new((temp, rvalue))));
680 match &mut self.blocks[switch] {
681 BasicBlockData { statements, terminator: Some(Terminator { kind, .. }), .. } => {
682 statements.push(statement);
683 *kind = TerminatorKind::SwitchInt {
684 discr: Operand::Move(temp),
685 targets: SwitchTargets::new(cases.into_iter(), unreachable),
686 };
687 }
688 BasicBlockData { terminator: None, .. } => unreachable!(),
689 }
690 }
691}
692
693#[instrument(level = "debug", skip(tcx), ret)]
696fn build_call_shim<'tcx>(
697 tcx: TyCtxt<'tcx>,
698 instance: ty::InstanceKind<'tcx>,
699 rcvr_adjustment: Option<Adjustment>,
700 call_kind: CallKind<'tcx>,
701) -> Body<'tcx> {
702 let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance {
706 let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx));
707
708 let untuple_args = sig.inputs();
709
710 let arg_tup = Ty::new_tup(tcx, untuple_args);
712
713 (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
714 } else {
715 (None, None)
716 };
717
718 let def_id = instance.def_id();
719
720 let sig = tcx.fn_sig(def_id);
721 let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));
722
723 assert_eq!(sig_args.is_some(), !instance.has_polymorphic_mir_body());
724 let mut sig = if let Some(sig_args) = sig_args {
725 sig.instantiate(tcx, &sig_args)
726 } else {
727 sig.instantiate_identity()
728 };
729
730 if let CallKind::Indirect(fnty) = call_kind {
731 let mut inputs_and_output = sig.inputs_and_output.to_vec();
737
738 assert_eq!(inputs_and_output.len(), 3);
741
742 let self_arg = &mut inputs_and_output[0];
745 *self_arg = match rcvr_adjustment.unwrap() {
746 Adjustment::Identity => fnty,
747 Adjustment::Deref { source } => match source {
748 DerefSource::ImmRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fnty),
749 DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty),
750 DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty),
751 },
752 Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"),
753 };
754 sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
755 }
756
757 if let ty::InstanceKind::VTableShim(..) = instance {
760 let mut inputs_and_output = sig.inputs_and_output.to_vec();
762 let self_arg = &mut inputs_and_output[0];
763 debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
764 *self_arg = Ty::new_mut_ptr(tcx, *self_arg);
765 sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
766 }
767
768 let span = tcx.def_span(def_id);
769
770 debug!(?sig);
771
772 let mut local_decls = local_decls_for_sig(&sig, span);
773 let source_info = SourceInfo::outermost(span);
774
775 let destination = Place::return_place();
776
777 let rcvr_place = || {
778 assert!(rcvr_adjustment.is_some());
779 Place::from(Local::new(1))
780 };
781 let mut statements = vec![];
782
783 let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
784 Adjustment::Identity => Operand::Move(rcvr_place()),
785 Adjustment::Deref { source: _ } => Operand::Move(tcx.mk_place_deref(rcvr_place())),
786 Adjustment::RefMut => {
787 let ref_rcvr = local_decls.push(
789 LocalDecl::new(
790 Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, sig.inputs()[0]),
791 span,
792 )
793 .immutable(),
794 );
795 let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default };
796 statements.push(Statement {
797 source_info,
798 kind: StatementKind::Assign(Box::new((
799 Place::from(ref_rcvr),
800 Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
801 ))),
802 });
803 Operand::Move(Place::from(ref_rcvr))
804 }
805 });
806
807 let (callee, mut args) = match call_kind {
808 CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
810
811 CallKind::Direct(def_id) => {
813 let ty = tcx.type_of(def_id).instantiate_identity();
814 (
815 Operand::Constant(Box::new(ConstOperand {
816 span,
817 user_ty: None,
818 const_: Const::zero_sized(ty),
819 })),
820 rcvr.into_iter().collect::<Vec<_>>(),
821 )
822 }
823 };
824
825 let mut arg_range = 0..sig.inputs().len();
826
827 if rcvr_adjustment.is_some() {
829 arg_range.start += 1;
830 }
831
832 if untuple_args.is_some() {
834 arg_range.end -= 1;
835 }
836
837 args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
839
840 if let Some(untuple_args) = untuple_args {
842 let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
843 args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
844 Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), FieldIdx::new(i), *ity))
845 }));
846 }
847
848 let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
849 let mut blocks = IndexVec::with_capacity(n_blocks);
850 let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
851 blocks.push(BasicBlockData {
852 statements,
853 terminator: Some(Terminator { source_info, kind }),
854 is_cleanup,
855 })
856 };
857
858 let args = args.into_iter().map(|a| Spanned { node: a, span: DUMMY_SP }).collect();
860 block(
861 &mut blocks,
862 statements,
863 TerminatorKind::Call {
864 func: callee,
865 args,
866 destination,
867 target: Some(BasicBlock::new(1)),
868 unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
869 UnwindAction::Cleanup(BasicBlock::new(3))
870 } else {
871 UnwindAction::Continue
872 },
873 call_source: CallSource::Misc,
874 fn_span: span,
875 },
876 false,
877 );
878
879 if let Some(Adjustment::RefMut) = rcvr_adjustment {
880 block(
882 &mut blocks,
883 vec![],
884 TerminatorKind::Drop {
885 place: rcvr_place(),
886 target: BasicBlock::new(2),
887 unwind: UnwindAction::Continue,
888 replace: false,
889 },
890 false,
891 );
892 }
893 let stmts = vec![];
895 block(&mut blocks, stmts, TerminatorKind::Return, false);
896 if let Some(Adjustment::RefMut) = rcvr_adjustment {
897 block(
899 &mut blocks,
900 vec![],
901 TerminatorKind::Drop {
902 place: rcvr_place(),
903 target: BasicBlock::new(4),
904 unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
905 replace: false,
906 },
907 true,
908 );
909
910 block(&mut blocks, vec![], TerminatorKind::UnwindResume, true);
912 }
913
914 let mut body =
915 new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
916
917 if let ExternAbi::RustCall = sig.abi {
918 body.spread_arg = Some(Local::new(sig.inputs().len()));
919 }
920
921 body
922}
923
924pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
925 debug_assert!(tcx.is_constructor(ctor_id));
926
927 let typing_env = ty::TypingEnv::post_analysis(tcx, ctor_id);
928
929 let sig = tcx
931 .fn_sig(ctor_id)
932 .instantiate_identity()
933 .no_bound_vars()
934 .expect("LBR in ADT constructor signature");
935 let sig = tcx.normalize_erasing_regions(typing_env, sig);
936
937 let ty::Adt(adt_def, args) = sig.output().kind() else {
938 bug!("unexpected type for ADT ctor {:?}", sig.output());
939 };
940
941 debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
942
943 let span = tcx.def_span(ctor_id);
944
945 let local_decls = local_decls_for_sig(&sig, span);
946
947 let source_info = SourceInfo::outermost(span);
948
949 let variant_index =
950 if adt_def.is_enum() { adt_def.variant_index_with_ctor_id(ctor_id) } else { FIRST_VARIANT };
951
952 debug!("build_ctor: variant_index={:?}", variant_index);
959
960 let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None);
961 let variant = adt_def.variant(variant_index);
962 let statement = Statement {
963 kind: StatementKind::Assign(Box::new((
964 Place::return_place(),
965 Rvalue::Aggregate(
966 Box::new(kind),
967 (0..variant.fields.len())
968 .map(|idx| Operand::Move(Place::from(Local::new(idx + 1))))
969 .collect(),
970 ),
971 ))),
972 source_info,
973 };
974
975 let start_block = BasicBlockData {
976 statements: vec![statement],
977 terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
978 is_cleanup: false,
979 };
980
981 let source = MirSource::item(ctor_id);
982 let mut body = new_body(
983 source,
984 IndexVec::from_elem_n(start_block, 1),
985 local_decls,
986 sig.inputs().len(),
987 span,
988 );
989 body.set_mentioned_items(Vec::new());
992
993 crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
994
995 body
996}
997
998fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
1006 assert_matches!(self_ty.kind(), ty::FnPtr(..), "expected fn ptr, found {self_ty}");
1007 let span = tcx.def_span(def_id);
1008 let Some(sig) = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]).no_bound_vars() else {
1009 span_bug!(span, "FnPtr::addr with bound vars for `{self_ty}`");
1010 };
1011 let locals = local_decls_for_sig(&sig, span);
1012
1013 let source_info = SourceInfo::outermost(span);
1014 let rvalue = Rvalue::Cast(
1017 CastKind::FnPtrToPtr,
1018 Operand::Move(Place::from(Local::new(1))),
1019 Ty::new_imm_ptr(tcx, tcx.types.unit),
1020 );
1021 let stmt = Statement {
1022 source_info,
1023 kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
1024 };
1025 let statements = vec![stmt];
1026 let start_block = BasicBlockData {
1027 statements,
1028 terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
1029 is_cleanup: false,
1030 };
1031 let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty));
1032 new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
1033}
1034
1035fn build_construct_coroutine_by_move_shim<'tcx>(
1036 tcx: TyCtxt<'tcx>,
1037 coroutine_closure_def_id: DefId,
1038 receiver_by_ref: bool,
1039) -> Body<'tcx> {
1040 let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
1041 let mut self_local: Place<'tcx> = Local::from_usize(1).into();
1042 let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
1043 bug!();
1044 };
1045
1046 if receiver_by_ref {
1052 self_local = tcx.mk_place_deref(self_local);
1053 self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty);
1054 }
1055
1056 let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
1057 tcx.mk_fn_sig(
1058 [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()),
1059 sig.to_coroutine_given_kind_and_upvars(
1060 tcx,
1061 args.as_coroutine_closure().parent_args(),
1062 tcx.coroutine_for_closure(coroutine_closure_def_id),
1063 ty::ClosureKind::FnOnce,
1064 tcx.lifetimes.re_erased,
1065 args.as_coroutine_closure().tupled_upvars_ty(),
1066 args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
1067 ),
1068 sig.c_variadic,
1069 sig.safety,
1070 sig.abi,
1071 )
1072 });
1073 let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig);
1074 let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else {
1075 bug!();
1076 };
1077
1078 let span = tcx.def_span(coroutine_closure_def_id);
1079 let locals = local_decls_for_sig(&sig, span);
1080
1081 let mut fields = vec![];
1082
1083 for idx in 1..sig.inputs().len() {
1085 fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
1086 }
1087
1088 for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
1089 if receiver_by_ref {
1090 if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) {
1094 tcx.dcx().delayed_bug(format!(
1098 "field should be captured by immutable ref if we have \
1099 an `Fn` instance, but it was: {ty}"
1100 ));
1101 }
1102 fields.push(Operand::Copy(tcx.mk_place_field(
1103 self_local,
1104 FieldIdx::from_usize(idx),
1105 ty,
1106 )));
1107 } else {
1108 fields.push(Operand::Move(tcx.mk_place_field(
1109 self_local,
1110 FieldIdx::from_usize(idx),
1111 ty,
1112 )));
1113 }
1114 }
1115
1116 let source_info = SourceInfo::outermost(span);
1117 let rvalue = Rvalue::Aggregate(
1118 Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
1119 IndexVec::from_raw(fields),
1120 );
1121 let stmt = Statement {
1122 source_info,
1123 kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
1124 };
1125 let statements = vec![stmt];
1126 let start_block = BasicBlockData {
1127 statements,
1128 terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
1129 is_cleanup: false,
1130 };
1131
1132 let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim {
1133 coroutine_closure_def_id,
1134 receiver_by_ref,
1135 });
1136
1137 let body =
1138 new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span);
1139 dump_mir(
1140 tcx,
1141 false,
1142 if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" },
1143 &0,
1144 &body,
1145 |_, _| Ok(()),
1146 );
1147
1148 body
1149}