2 use rustc_hir
::def_id
::DefId
;
3 use rustc_hir
::lang_items
::LangItem
;
4 use rustc_middle
::mir
::*;
5 use rustc_middle
::ty
::query
::Providers
;
6 use rustc_middle
::ty
::subst
::{InternalSubsts, Subst}
;
7 use rustc_middle
::ty
::{self, Ty, TyCtxt}
;
8 use rustc_target
::abi
::VariantIdx
;
10 use rustc_index
::vec
::{Idx, IndexVec}
;
13 use rustc_target
::spec
::abi
::Abi
;
18 use crate::transform
::{
19 add_call_guards
, add_moves_for_packed_drops
, no_landing_pads
, remove_noop_landing_pads
,
22 use crate::util
::elaborate_drops
::{self, DropElaborator, DropFlagMode, DropStyle}
;
23 use crate::util
::expand_aggregate
;
24 use crate::util
::patch
::MirPatch
;
26 pub fn provide(providers
: &mut Providers
) {
27 providers
.mir_shims
= make_shim
;
30 fn make_shim
<'tcx
>(tcx
: TyCtxt
<'tcx
>, instance
: ty
::InstanceDef
<'tcx
>) -> Body
<'tcx
> {
31 debug
!("make_shim({:?})", instance
);
33 let mut result
= match instance
{
34 ty
::InstanceDef
::Item(..) => bug
!("item {:?} passed to make_shim", instance
),
35 ty
::InstanceDef
::VtableShim(def_id
) => {
36 build_call_shim(tcx
, instance
, Some(Adjustment
::Deref
), CallKind
::Direct(def_id
))
38 ty
::InstanceDef
::FnPtrShim(def_id
, ty
) => {
39 let trait_
= tcx
.trait_of_item(def_id
).unwrap();
40 let adjustment
= match tcx
.fn_trait_kind_from_lang_item(trait_
) {
41 Some(ty
::ClosureKind
::FnOnce
) => Adjustment
::Identity
,
42 Some(ty
::ClosureKind
::FnMut
| ty
::ClosureKind
::Fn
) => Adjustment
::Deref
,
43 None
=> bug
!("fn pointer {:?} is not an fn", ty
),
46 build_call_shim(tcx
, instance
, Some(adjustment
), CallKind
::Indirect(ty
))
48 // We are generating a call back to our def-id, which the
49 // codegen backend knows to turn to an actual call, be it
50 // a virtual call, or a direct call to a function for which
51 // indirect calls must be codegen'd differently than direct ones
52 // (such as `#[track_caller]`).
53 ty
::InstanceDef
::ReifyShim(def_id
) => {
54 build_call_shim(tcx
, instance
, None
, CallKind
::Direct(def_id
))
56 ty
::InstanceDef
::ClosureOnceShim { call_once: _ }
=> {
57 let fn_mut
= tcx
.require_lang_item(LangItem
::FnMut
, None
);
59 .associated_items(fn_mut
)
60 .in_definition_order()
61 .find(|it
| it
.kind
== ty
::AssocKind
::Fn
)
65 build_call_shim(tcx
, instance
, Some(Adjustment
::RefMut
), CallKind
::Direct(call_mut
))
67 ty
::InstanceDef
::DropGlue(def_id
, ty
) => build_drop_shim(tcx
, def_id
, ty
),
68 ty
::InstanceDef
::CloneShim(def_id
, ty
) => build_clone_shim(tcx
, def_id
, ty
),
69 ty
::InstanceDef
::Virtual(..) => {
70 bug
!("InstanceDef::Virtual ({:?}) is for direct calls only", instance
)
72 ty
::InstanceDef
::Intrinsic(_
) => {
73 bug
!("creating shims from intrinsics ({:?}) is unsupported", instance
)
76 debug
!("make_shim({:?}) = untransformed {:?}", instance
, result
);
85 &add_moves_for_packed_drops
::AddMovesForPackedDrops
,
86 &no_landing_pads
::NoLandingPads
::new(tcx
),
87 &remove_noop_landing_pads
::RemoveNoopLandingPads
,
88 &simplify
::SimplifyCfg
::new("make_shim"),
89 &add_call_guards
::CriticalCallEdges
,
93 debug
!("make_shim({:?}) = {:?}", instance
, result
);
98 #[derive(Copy, Clone, Debug, PartialEq)]
100 /// Pass the receiver as-is.
103 /// We get passed `&[mut] self` and call the target with `*self`.
105 /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
106 /// (for `VtableShim`, which effectively is passed `&own Self`).
109 /// We get passed `self: Self` and call the target with `&mut self`.
111 /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
112 /// won't do it for us.
116 #[derive(Copy, Clone, Debug, PartialEq)]
117 enum CallKind
<'tcx
> {
118 /// Call the `FnPtr` that was passed as the receiver.
121 /// Call a known `FnDef`.
125 fn local_decls_for_sig
<'tcx
>(
126 sig
: &ty
::FnSig
<'tcx
>,
128 ) -> IndexVec
<Local
, LocalDecl
<'tcx
>> {
129 iter
::once(LocalDecl
::new(sig
.output(), span
))
130 .chain(sig
.inputs().iter().map(|ity
| LocalDecl
::new(ity
, span
).immutable()))
134 fn build_drop_shim
<'tcx
>(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
, ty
: Option
<Ty
<'tcx
>>) -> Body
<'tcx
> {
135 debug
!("build_drop_shim(def_id={:?}, ty={:?})", def_id
, ty
);
137 // Check if this is a generator, if so, return the drop glue for it
138 if let Some(&ty
::Generator(gen_def_id
, substs
, _
)) = ty
.map(|ty
| ty
.kind()) {
139 let body
= &**tcx
.optimized_mir(gen_def_id
).generator_drop
.as_ref().unwrap();
140 return body
.subst(tcx
, substs
);
143 let substs
= if let Some(ty
) = ty
{
144 tcx
.intern_substs(&[ty
.into()])
146 InternalSubsts
::identity_for_item(tcx
, def_id
)
148 let sig
= tcx
.fn_sig(def_id
).subst(tcx
, substs
);
149 let sig
= tcx
.erase_late_bound_regions(&sig
);
150 let span
= tcx
.def_span(def_id
);
152 let source_info
= SourceInfo
::outermost(span
);
154 let return_block
= BasicBlock
::new(1);
155 let mut blocks
= IndexVec
::with_capacity(2);
156 let block
= |blocks
: &mut IndexVec
<_
, _
>, kind
| {
157 blocks
.push(BasicBlockData
{
159 terminator
: Some(Terminator { source_info, kind }
),
163 block(&mut blocks
, TerminatorKind
::Goto { target: return_block }
);
164 block(&mut blocks
, TerminatorKind
::Return
);
166 let mut body
= new_body(blocks
, local_decls_for_sig(&sig
, span
), sig
.inputs().len(), span
);
168 if let Some(..) = ty
{
169 // The first argument (index 0), but add 1 for the return value.
170 let dropee_ptr
= Place
::from(Local
::new(1 + 0));
171 if tcx
.sess
.opts
.debugging_opts
.mir_emit_retag
{
172 // Function arguments should be retagged, and we make this one raw.
173 body
.basic_blocks_mut()[START_BLOCK
].statements
.insert(
177 kind
: StatementKind
::Retag(RetagKind
::Raw
, box (dropee_ptr
)),
182 let param_env
= tcx
.param_env_reveal_all_normalized(def_id
);
184 DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env }
;
185 let dropee
= tcx
.mk_place_deref(dropee_ptr
);
186 let resume_block
= elaborator
.patch
.resume_block();
187 elaborate_drops
::elaborate_drop(
193 elaborate_drops
::Unwind
::To(resume_block
),
198 patch
.apply(&mut body
);
205 basic_blocks
: IndexVec
<BasicBlock
, BasicBlockData
<'tcx
>>,
206 local_decls
: IndexVec
<Local
, LocalDecl
<'tcx
>>,
212 IndexVec
::from_elem_n(
213 SourceScopeData { span, parent_scope: None, local_data: ClearCrossCrate::Clear }
,
225 pub struct DropShimElaborator
<'a
, 'tcx
> {
226 pub body
: &'a Body
<'tcx
>,
227 pub patch
: MirPatch
<'tcx
>,
228 pub tcx
: TyCtxt
<'tcx
>,
229 pub param_env
: ty
::ParamEnv
<'tcx
>,
232 impl<'a
, 'tcx
> fmt
::Debug
for DropShimElaborator
<'a
, 'tcx
> {
233 fn fmt(&self, _f
: &mut fmt
::Formatter
<'_
>) -> Result
<(), fmt
::Error
> {
238 impl<'a
, 'tcx
> DropElaborator
<'a
, 'tcx
> for DropShimElaborator
<'a
, 'tcx
> {
241 fn patch(&mut self) -> &mut MirPatch
<'tcx
> {
244 fn body(&self) -> &'a Body
<'tcx
> {
247 fn tcx(&self) -> TyCtxt
<'tcx
> {
250 fn param_env(&self) -> ty
::ParamEnv
<'tcx
> {
254 fn drop_style(&self, _path
: Self::Path
, mode
: DropFlagMode
) -> DropStyle
{
256 DropFlagMode
::Shallow
=> {
257 // Drops for the contained fields are "shallow" and "static" - they will simply call
258 // the field's own drop glue.
261 DropFlagMode
::Deep
=> {
262 // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
263 // dropping each field contained in the value.
269 fn get_drop_flag(&mut self, _path
: Self::Path
) -> Option
<Operand
<'tcx
>> {
273 fn clear_drop_flag(&mut self, _location
: Location
, _path
: Self::Path
, _mode
: DropFlagMode
) {}
275 fn field_subpath(&self, _path
: Self::Path
, _field
: Field
) -> Option
<Self::Path
> {
278 fn deref_subpath(&self, _path
: Self::Path
) -> Option
<Self::Path
> {
281 fn downcast_subpath(&self, _path
: Self::Path
, _variant
: VariantIdx
) -> Option
<Self::Path
> {
284 fn array_subpath(&self, _path
: Self::Path
, _index
: u64, _size
: u64) -> Option
<Self::Path
> {
289 /// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
290 fn build_clone_shim
<'tcx
>(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
, self_ty
: Ty
<'tcx
>) -> Body
<'tcx
> {
291 debug
!("build_clone_shim(def_id={:?})", def_id
);
293 let param_env
= tcx
.param_env(def_id
);
295 let mut builder
= CloneShimBuilder
::new(tcx
, def_id
, self_ty
);
296 let is_copy
= self_ty
.is_copy_modulo_regions(tcx
.at(builder
.span
), param_env
);
298 let dest
= Place
::return_place();
299 let src
= tcx
.mk_place_deref(Place
::from(Local
::new(1 + 0)));
301 match self_ty
.kind() {
302 _
if is_copy
=> builder
.copy_shim(),
303 ty
::Array(ty
, len
) => {
304 let len
= len
.eval_usize(tcx
, param_env
);
305 builder
.array_shim(dest
, src
, ty
, len
)
307 ty
::Closure(_
, substs
) => {
308 builder
.tuple_like_shim(dest
, src
, substs
.as_closure().upvar_tys())
310 ty
::Tuple(..) => builder
.tuple_like_shim(dest
, src
, self_ty
.tuple_fields()),
311 _
=> bug
!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty
),
317 struct CloneShimBuilder
<'tcx
> {
320 local_decls
: IndexVec
<Local
, LocalDecl
<'tcx
>>,
321 blocks
: IndexVec
<BasicBlock
, BasicBlockData
<'tcx
>>,
323 sig
: ty
::FnSig
<'tcx
>,
326 impl CloneShimBuilder
<'tcx
> {
327 fn new(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
, self_ty
: Ty
<'tcx
>) -> Self {
328 // we must subst the self_ty because it's
329 // otherwise going to be TySelf and we can't index
330 // or access fields of a Place of type TySelf.
331 let substs
= tcx
.mk_substs_trait(self_ty
, &[]);
332 let sig
= tcx
.fn_sig(def_id
).subst(tcx
, substs
);
333 let sig
= tcx
.erase_late_bound_regions(&sig
);
334 let span
= tcx
.def_span(def_id
);
339 local_decls
: local_decls_for_sig(&sig
, span
),
340 blocks
: IndexVec
::new(),
346 fn into_mir(self) -> Body
<'tcx
> {
347 new_body(self.blocks
, self.local_decls
, self.sig
.inputs().len(), self.span
)
350 fn source_info(&self) -> SourceInfo
{
351 SourceInfo
::outermost(self.span
)
356 statements
: Vec
<Statement
<'tcx
>>,
357 kind
: TerminatorKind
<'tcx
>,
360 let source_info
= self.source_info();
361 self.blocks
.push(BasicBlockData
{
363 terminator
: Some(Terminator { source_info, kind }
),
368 /// Gives the index of an upcoming BasicBlock, with an offset.
369 /// offset=0 will give you the index of the next BasicBlock,
370 /// offset=1 will give the index of the next-to-next block,
371 /// offset=-1 will give you the index of the last-created block
372 fn block_index_offset(&mut self, offset
: usize) -> BasicBlock
{
373 BasicBlock
::new(self.blocks
.len() + offset
)
376 fn make_statement(&self, kind
: StatementKind
<'tcx
>) -> Statement
<'tcx
> {
377 Statement { source_info: self.source_info(), kind }
380 fn copy_shim(&mut self) {
381 let rcvr
= self.tcx
.mk_place_deref(Place
::from(Local
::new(1 + 0)));
382 let ret_statement
= self.make_statement(StatementKind
::Assign(box (
383 Place
::return_place(),
384 Rvalue
::Use(Operand
::Copy(rcvr
)),
386 self.block(vec
![ret_statement
], TerminatorKind
::Return
, false);
389 fn make_place(&mut self, mutability
: Mutability
, ty
: Ty
<'tcx
>) -> Place
<'tcx
> {
390 let span
= self.span
;
391 let mut local
= LocalDecl
::new(ty
, span
);
392 if mutability
== Mutability
::Not
{
393 local
= local
.immutable();
395 Place
::from(self.local_decls
.push(local
))
408 let substs
= tcx
.mk_substs_trait(ty
, &[]);
410 // `func == Clone::clone(&ty) -> ty`
411 let func_ty
= tcx
.mk_fn_def(self.def_id
, substs
);
412 let func
= Operand
::Constant(box Constant
{
415 literal
: ty
::Const
::zero_sized(tcx
, func_ty
),
418 let ref_loc
= self.make_place(
420 tcx
.mk_ref(tcx
.lifetimes
.re_erased
, ty
::TypeAndMut { ty, mutbl: hir::Mutability::Not }
),
423 // `let ref_loc: &ty = &src;`
424 let statement
= self.make_statement(StatementKind
::Assign(box (
426 Rvalue
::Ref(tcx
.lifetimes
.re_erased
, BorrowKind
::Shared
, src
),
429 // `let loc = Clone::clone(ref_loc);`
432 TerminatorKind
::Call
{
434 args
: vec
![Operand
::Move(ref_loc
)],
435 destination
: Some((dest
, next
)),
436 cleanup
: Some(cleanup
),
448 loop_body
: BasicBlock
,
449 loop_end
: BasicBlock
,
454 let cond
= self.make_place(Mutability
::Mut
, tcx
.types
.bool
);
455 let compute_cond
= self.make_statement(StatementKind
::Assign(box (
457 Rvalue
::BinaryOp(BinOp
::Ne
, Operand
::Copy(end
), Operand
::Copy(beg
)),
460 // `if end != beg { goto loop_body; } else { goto loop_end; }`
463 TerminatorKind
::if_(tcx
, Operand
::Move(cond
), loop_body
, loop_end
),
468 fn make_usize(&self, value
: u64) -> Box
<Constant
<'tcx
>> {
472 literal
: ty
::Const
::from_usize(self.tcx
, value
),
476 fn array_shim(&mut self, dest
: Place
<'tcx
>, src
: Place
<'tcx
>, ty
: Ty
<'tcx
>, len
: u64) {
478 let span
= self.span
;
480 let beg
= self.local_decls
.push(LocalDecl
::new(tcx
.types
.usize, span
));
481 let end
= self.make_place(Mutability
::Not
, tcx
.types
.usize);
484 // `let mut beg = 0;`
488 self.make_statement(StatementKind
::Assign(box (
490 Rvalue
::Use(Operand
::Constant(self.make_usize(0))),
492 self.make_statement(StatementKind
::Assign(box (
494 Rvalue
::Use(Operand
::Constant(self.make_usize(len
))),
497 self.block(inits
, TerminatorKind
::Goto { target: BasicBlock::new(1) }
, false);
504 self.loop_header(Place
::from(beg
), end
, BasicBlock
::new(2), BasicBlock
::new(4), false);
507 // `dest[i] = Clone::clone(src[beg])`;
508 // Goto #3 if ok, #5 if unwinding happens.
509 let dest_field
= self.tcx
.mk_place_index(dest
, beg
);
510 let src_field
= self.tcx
.mk_place_index(src
, beg
);
511 self.make_clone_call(dest_field
, src_field
, ty
, BasicBlock
::new(3), BasicBlock
::new(5));
516 let statements
= vec
![self.make_statement(StatementKind
::Assign(box (
520 Operand
::Copy(Place
::from(beg
)),
521 Operand
::Constant(self.make_usize(1)),
524 self.block(statements
, TerminatorKind
::Goto { target: BasicBlock::new(1) }
, false);
528 self.block(vec
![], TerminatorKind
::Return
, false);
532 // `let mut beg = 0;`
535 let beg
= self.local_decls
.push(LocalDecl
::new(tcx
.types
.usize, span
));
536 let init
= self.make_statement(StatementKind
::Assign(box (
538 Rvalue
::Use(Operand
::Constant(self.make_usize(0))),
540 self.block(vec
![init
], TerminatorKind
::Goto { target: BasicBlock::new(6) }
, true);
542 // BB #6 (cleanup): loop {
556 // `drop(dest[beg])`;
559 TerminatorKind
::Drop
{
560 place
: self.tcx
.mk_place_index(dest
, beg
),
561 target
: BasicBlock
::new(8),
570 let statement
= self.make_statement(StatementKind
::Assign(box (
574 Operand
::Copy(Place
::from(beg
)),
575 Operand
::Constant(self.make_usize(1)),
578 self.block(vec
![statement
], TerminatorKind
::Goto { target: BasicBlock::new(6) }
, true);
581 self.block(vec
![], TerminatorKind
::Resume
, true);
584 fn tuple_like_shim
<I
>(&mut self, dest
: Place
<'tcx
>, src
: Place
<'tcx
>, tys
: I
)
586 I
: Iterator
<Item
= Ty
<'tcx
>>,
588 let mut previous_field
= None
;
589 for (i
, ity
) in tys
.enumerate() {
590 let field
= Field
::new(i
);
591 let src_field
= self.tcx
.mk_place_field(src
, field
, ity
);
593 let dest_field
= self.tcx
.mk_place_field(dest
, field
, ity
);
595 // #(2i + 1) is the cleanup block for the previous clone operation
596 let cleanup_block
= self.block_index_offset(1);
597 // #(2i + 2) is the next cloning block
598 // (or the Return terminator if this is the last block)
599 let next_block
= self.block_index_offset(2);
602 // `dest.i = Clone::clone(&src.i);`
603 // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
604 self.make_clone_call(dest_field
, src_field
, ity
, next_block
, cleanup_block
);
606 // BB #(2i + 1) (cleanup)
607 if let Some((previous_field
, previous_cleanup
)) = previous_field
.take() {
608 // Drop previous field and goto previous cleanup block.
611 TerminatorKind
::Drop
{
612 place
: previous_field
,
613 target
: previous_cleanup
,
619 // Nothing to drop, just resume.
620 self.block(vec
![], TerminatorKind
::Resume
, true);
623 previous_field
= Some((dest_field
, cleanup_block
));
626 self.block(vec
![], TerminatorKind
::Return
, false);
630 /// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
631 /// first adjusting its first argument according to `rcvr_adjustment`.
632 fn build_call_shim
<'tcx
>(
634 instance
: ty
::InstanceDef
<'tcx
>,
635 rcvr_adjustment
: Option
<Adjustment
>,
636 call_kind
: CallKind
<'tcx
>,
639 "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})",
640 instance
, rcvr_adjustment
, call_kind
643 // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
644 // to substitute into the signature of the shim. It is not necessary for users of this
645 // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
646 let (sig_substs
, untuple_args
) = if let ty
::InstanceDef
::FnPtrShim(_
, ty
) = instance
{
647 let sig
= tcx
.erase_late_bound_regions(&ty
.fn_sig(tcx
));
649 let untuple_args
= sig
.inputs();
651 // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
652 let arg_tup
= tcx
.mk_tup(untuple_args
.iter());
653 let sig_substs
= tcx
.mk_substs_trait(ty
, &[ty
::subst
::GenericArg
::from(arg_tup
)]);
655 (Some(sig_substs
), Some(untuple_args
))
660 let def_id
= instance
.def_id();
661 let sig
= tcx
.fn_sig(def_id
);
662 let mut sig
= tcx
.erase_late_bound_regions(&sig
);
664 assert_eq
!(sig_substs
.is_some(), !instance
.has_polymorphic_mir_body());
665 if let Some(sig_substs
) = sig_substs
{
666 sig
= sig
.subst(tcx
, sig_substs
);
669 if let CallKind
::Indirect(fnty
) = call_kind
{
670 // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
671 // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
672 // the implemented `FnX` trait.
674 // Apply the opposite adjustment to the MIR input.
675 let mut inputs_and_output
= sig
.inputs_and_output
.to_vec();
677 // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
678 // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
679 assert_eq
!(inputs_and_output
.len(), 3);
681 // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
682 // `FnDef` and `FnPtr` callees, not the `Self` type param.
683 let self_arg
= &mut inputs_and_output
[0];
684 *self_arg
= match rcvr_adjustment
.unwrap() {
685 Adjustment
::Identity
=> fnty
,
686 Adjustment
::Deref
=> tcx
.mk_imm_ptr(fnty
),
687 Adjustment
::RefMut
=> tcx
.mk_mut_ptr(fnty
),
689 sig
.inputs_and_output
= tcx
.intern_type_list(&inputs_and_output
);
692 // FIXME(eddyb) avoid having this snippet both here and in
693 // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
694 if let ty
::InstanceDef
::VtableShim(..) = instance
{
695 // Modify fn(self, ...) to fn(self: *mut Self, ...)
696 let mut inputs_and_output
= sig
.inputs_and_output
.to_vec();
697 let self_arg
= &mut inputs_and_output
[0];
698 debug_assert
!(tcx
.generics_of(def_id
).has_self
&& *self_arg
== tcx
.types
.self_param
);
699 *self_arg
= tcx
.mk_mut_ptr(*self_arg
);
700 sig
.inputs_and_output
= tcx
.intern_type_list(&inputs_and_output
);
703 let span
= tcx
.def_span(def_id
);
705 debug
!("build_call_shim: sig={:?}", sig
);
707 let mut local_decls
= local_decls_for_sig(&sig
, span
);
708 let source_info
= SourceInfo
::outermost(span
);
710 let rcvr_place
= || {
711 assert
!(rcvr_adjustment
.is_some());
712 Place
::from(Local
::new(1 + 0))
714 let mut statements
= vec
![];
716 let rcvr
= rcvr_adjustment
.map(|rcvr_adjustment
| match rcvr_adjustment
{
717 Adjustment
::Identity
=> Operand
::Move(rcvr_place()),
718 Adjustment
::Deref
=> Operand
::Move(tcx
.mk_place_deref(rcvr_place())),
719 Adjustment
::RefMut
=> {
720 // let rcvr = &mut rcvr;
721 let ref_rcvr
= local_decls
.push(
724 tcx
.lifetimes
.re_erased
,
725 ty
::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut }
,
731 let borrow_kind
= BorrowKind
::Mut { allow_two_phase_borrow: false }
;
732 statements
.push(Statement
{
734 kind
: StatementKind
::Assign(box (
735 Place
::from(ref_rcvr
),
736 Rvalue
::Ref(tcx
.lifetimes
.re_erased
, borrow_kind
, rcvr_place()),
739 Operand
::Move(Place
::from(ref_rcvr
))
743 let (callee
, mut args
) = match call_kind
{
744 // `FnPtr` call has no receiver. Args are untupled below.
745 CallKind
::Indirect(_
) => (rcvr
.unwrap(), vec
![]),
747 // `FnDef` call with optional receiver.
748 CallKind
::Direct(def_id
) => {
749 let ty
= tcx
.type_of(def_id
);
751 Operand
::Constant(box Constant
{
754 literal
: ty
::Const
::zero_sized(tcx
, ty
),
756 rcvr
.into_iter().collect
::<Vec
<_
>>(),
761 let mut arg_range
= 0..sig
.inputs().len();
763 // Take the `self` ("receiver") argument out of the range (it's adjusted above).
764 if rcvr_adjustment
.is_some() {
765 arg_range
.start
+= 1;
768 // Take the last argument, if we need to untuple it (handled below).
769 if untuple_args
.is_some() {
773 // Pass all of the non-special arguments directly.
774 args
.extend(arg_range
.map(|i
| Operand
::Move(Place
::from(Local
::new(1 + i
)))));
776 // Untuple the last argument, if we have to.
777 if let Some(untuple_args
) = untuple_args
{
778 let tuple_arg
= Local
::new(1 + (sig
.inputs().len() - 1));
779 args
.extend(untuple_args
.iter().enumerate().map(|(i
, ity
)| {
780 Operand
::Move(tcx
.mk_place_field(Place
::from(tuple_arg
), Field
::new(i
), *ity
))
784 let n_blocks
= if let Some(Adjustment
::RefMut
) = rcvr_adjustment { 5 }
else { 2 }
;
785 let mut blocks
= IndexVec
::with_capacity(n_blocks
);
786 let block
= |blocks
: &mut IndexVec
<_
, _
>, statements
, kind
, is_cleanup
| {
787 blocks
.push(BasicBlockData
{
789 terminator
: Some(Terminator { source_info, kind }
),
798 TerminatorKind
::Call
{
801 destination
: Some((Place
::return_place(), BasicBlock
::new(1))),
802 cleanup
: if let Some(Adjustment
::RefMut
) = rcvr_adjustment
{
803 Some(BasicBlock
::new(3))
813 if let Some(Adjustment
::RefMut
) = rcvr_adjustment
{
814 // BB #1 - drop for Self
818 TerminatorKind
::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }
,
823 block(&mut blocks
, vec
![], TerminatorKind
::Return
, false);
824 if let Some(Adjustment
::RefMut
) = rcvr_adjustment
{
825 // BB #3 - drop if closure panics
829 TerminatorKind
::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }
,
834 block(&mut blocks
, vec
![], TerminatorKind
::Resume
, true);
837 let mut body
= new_body(blocks
, local_decls
, sig
.inputs().len(), span
);
839 if let Abi
::RustCall
= sig
.abi
{
840 body
.spread_arg
= Some(Local
::new(sig
.inputs().len()));
846 pub fn build_adt_ctor(tcx
: TyCtxt
<'_
>, ctor_id
: DefId
) -> Body
<'_
> {
847 debug_assert
!(tcx
.is_constructor(ctor_id
));
850 tcx
.hir().span_if_local(ctor_id
).unwrap_or_else(|| bug
!("no span for ctor {:?}", ctor_id
));
852 let param_env
= tcx
.param_env(ctor_id
);
854 // Normalize the sig.
855 let sig
= tcx
.fn_sig(ctor_id
).no_bound_vars().expect("LBR in ADT constructor signature");
856 let sig
= tcx
.normalize_erasing_regions(param_env
, sig
);
858 let (adt_def
, substs
) = match sig
.output().kind() {
859 ty
::Adt(adt_def
, substs
) => (adt_def
, substs
),
860 _
=> bug
!("unexpected type for ADT ctor {:?}", sig
.output()),
863 debug
!("build_ctor: ctor_id={:?} sig={:?}", ctor_id
, sig
);
865 let local_decls
= local_decls_for_sig(&sig
, span
);
867 let source_info
= SourceInfo
::outermost(span
);
869 let variant_index
= if adt_def
.is_enum() {
870 adt_def
.variant_index_with_ctor_id(ctor_id
)
875 // Generate the following MIR:
877 // (return as Variant).field0 = arg0;
878 // (return as Variant).field1 = arg1;
881 debug
!("build_ctor: variant_index={:?}", variant_index
);
883 let statements
= expand_aggregate(
884 Place
::return_place(),
885 adt_def
.variants
[variant_index
].fields
.iter().enumerate().map(|(idx
, field_def
)| {
886 (Operand
::Move(Place
::from(Local
::new(idx
+ 1))), field_def
.ty(tcx
, substs
))
888 AggregateKind
::Adt(adt_def
, variant_index
, substs
, None
, None
),
894 let start_block
= BasicBlockData
{
896 terminator
: Some(Terminator { source_info, kind: TerminatorKind::Return }
),
901 new_body(IndexVec
::from_elem_n(start_block
, 1), local_decls
, sig
.inputs().len(), span
);
903 crate::util
::dump_mir(
908 crate::transform
::MirSource
::item(ctor_id
),