]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/shim.rs
b4477d9c86d4370c69977d7c6c955d4e75e8b6b0
[rust.git] / src / librustc_mir / shim.rs
1 use rustc_hir as hir;
2 use rustc_hir::def_id::DefId;
3 use rustc_hir::lang_items::FnMutTraitLangItem;
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, TypeFoldable};
8 use rustc_target::abi::VariantIdx;
9
10 use rustc_index::vec::{Idx, IndexVec};
11
12 use rustc_span::Span;
13 use rustc_target::spec::abi::Abi;
14
15 use std::fmt;
16 use std::iter;
17
18 use crate::transform::{
19     add_call_guards, add_moves_for_packed_drops, no_landing_pads, remove_noop_landing_pads,
20     run_passes, simplify,
21 };
22 use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
23 use crate::util::expand_aggregate;
24 use crate::util::patch::MirPatch;
25
26 pub fn provide(providers: &mut Providers<'_>) {
27     providers.mir_shims = make_shim;
28 }
29
30 fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> {
31     debug!("make_shim({:?})", instance);
32
33     let mut result = match instance {
34         ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
35         ty::InstanceDef::VtableShim(def_id) => build_call_shim(
36             tcx,
37             instance,
38             Some(Adjustment::DerefMove),
39             CallKind::Direct(def_id),
40             None,
41         ),
42         ty::InstanceDef::FnPtrShim(def_id, ty) => {
43             // FIXME(eddyb) support generating shims for a "shallow type",
44             // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
45             // `Foo<Bar>` or `[String]` etc.
46             assert!(!ty.needs_subst());
47
48             let trait_ = tcx.trait_of_item(def_id).unwrap();
49             let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) {
50                 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
51                 Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
52                 None => bug!("fn pointer {:?} is not an fn", ty),
53             };
54             // HACK: we need the "real" argument types for the MIR,
55             // but because our substs are (Self, Args), where Args
56             // is a tuple, we must include the *concrete* argument
57             // types in the MIR. They will be substituted again with
58             // the param-substs, but because they are concrete, this
59             // will not do any harm.
60             let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
61             let arg_tys = sig.inputs();
62
63             build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
64         }
65         // We are generating a call back to our def-id, which the
66         // codegen backend knows to turn to an actual call, be it
67         // a virtual call, or a direct call to a function for which
68         // indirect calls must be codegen'd differently than direct ones
69         // (such as `#[track_caller]`).
70         ty::InstanceDef::ReifyShim(def_id) => {
71             build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
72         }
73         ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
74             let fn_mut = tcx.require_lang_item(FnMutTraitLangItem, None);
75             let call_mut = tcx
76                 .associated_items(fn_mut)
77                 .in_definition_order()
78                 .find(|it| it.kind == ty::AssocKind::Fn)
79                 .unwrap()
80                 .def_id;
81
82             build_call_shim(
83                 tcx,
84                 instance,
85                 Some(Adjustment::RefMut),
86                 CallKind::Direct(call_mut),
87                 None,
88             )
89         }
90         ty::InstanceDef::DropGlue(def_id, ty) => {
91             // FIXME(eddyb) support generating shims for a "shallow type",
92             // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
93             // `Foo<Bar>` or `[String]` etc.
94             assert!(!ty.needs_subst());
95
96             build_drop_shim(tcx, def_id, ty)
97         }
98         ty::InstanceDef::CloneShim(def_id, ty) => {
99             // FIXME(eddyb) support generating shims for a "shallow type",
100             // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
101             // `Foo<Bar>` or `[String]` etc.
102             assert!(!ty.needs_subst());
103
104             build_clone_shim(tcx, def_id, ty)
105         }
106         ty::InstanceDef::Virtual(..) => {
107             bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
108         }
109         ty::InstanceDef::Intrinsic(_) => {
110             bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
111         }
112         ty::InstanceDef::InjectedCode(_) => {
113             bug!("creating shims from injected code ({:?}) is unsupported", instance)
114         }
115     };
116     debug!("make_shim({:?}) = untransformed {:?}", instance, result);
117
118     run_passes(
119         tcx,
120         &mut result,
121         instance,
122         None,
123         MirPhase::Const,
124         &[&[
125             &add_moves_for_packed_drops::AddMovesForPackedDrops,
126             &no_landing_pads::NoLandingPads::new(tcx),
127             &remove_noop_landing_pads::RemoveNoopLandingPads,
128             &simplify::SimplifyCfg::new("make_shim"),
129             &add_call_guards::CriticalCallEdges,
130         ]],
131     );
132
133     debug!("make_shim({:?}) = {:?}", instance, result);
134
135     result
136 }
137
138 #[derive(Copy, Clone, Debug, PartialEq)]
139 enum Adjustment {
140     Identity,
141     Deref,
142     DerefMove,
143     RefMut,
144 }
145
146 #[derive(Copy, Clone, Debug, PartialEq)]
147 enum CallKind {
148     Indirect,
149     Direct(DefId),
150 }
151
152 fn local_decls_for_sig<'tcx>(
153     sig: &ty::FnSig<'tcx>,
154     span: Span,
155 ) -> IndexVec<Local, LocalDecl<'tcx>> {
156     iter::once(LocalDecl::new(sig.output(), span))
157         .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable()))
158         .collect()
159 }
160
161 fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
162     debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
163
164     // Check if this is a generator, if so, return the drop glue for it
165     if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty {
166         let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap();
167         return body.subst(tcx, substs);
168     }
169
170     let substs = if let Some(ty) = ty {
171         tcx.intern_substs(&[ty.into()])
172     } else {
173         InternalSubsts::identity_for_item(tcx, def_id)
174     };
175     let sig = tcx.fn_sig(def_id).subst(tcx, substs);
176     let sig = tcx.erase_late_bound_regions(&sig);
177     let span = tcx.def_span(def_id);
178
179     let source_info = SourceInfo::outermost(span);
180
181     let return_block = BasicBlock::new(1);
182     let mut blocks = IndexVec::with_capacity(2);
183     let block = |blocks: &mut IndexVec<_, _>, kind| {
184         blocks.push(BasicBlockData {
185             statements: vec![],
186             terminator: Some(Terminator { source_info, kind }),
187             is_cleanup: false,
188         })
189     };
190     block(&mut blocks, TerminatorKind::Goto { target: return_block });
191     block(&mut blocks, TerminatorKind::Return);
192
193     let mut body = new_body(blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
194
195     if let Some(..) = ty {
196         // The first argument (index 0), but add 1 for the return value.
197         let dropee_ptr = Place::from(Local::new(1 + 0));
198         if tcx.sess.opts.debugging_opts.mir_emit_retag {
199             // Function arguments should be retagged, and we make this one raw.
200             body.basic_blocks_mut()[START_BLOCK].statements.insert(
201                 0,
202                 Statement {
203                     source_info,
204                     kind: StatementKind::Retag(RetagKind::Raw, box (dropee_ptr)),
205                 },
206             );
207         }
208         let patch = {
209             let param_env = tcx.param_env(def_id).with_reveal_all();
210             let mut elaborator =
211                 DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
212             let dropee = tcx.mk_place_deref(dropee_ptr);
213             let resume_block = elaborator.patch.resume_block();
214             elaborate_drops::elaborate_drop(
215                 &mut elaborator,
216                 source_info,
217                 dropee,
218                 (),
219                 return_block,
220                 elaborate_drops::Unwind::To(resume_block),
221                 START_BLOCK,
222             );
223             elaborator.patch
224         };
225         patch.apply(&mut body);
226     }
227
228     body
229 }
230
231 fn new_body<'tcx>(
232     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
233     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
234     arg_count: usize,
235     span: Span,
236 ) -> Body<'tcx> {
237     Body::new(
238         basic_blocks,
239         IndexVec::from_elem_n(
240             SourceScopeData { span, parent_scope: None, local_data: ClearCrossCrate::Clear },
241             1,
242         ),
243         local_decls,
244         IndexVec::new(),
245         arg_count,
246         vec![],
247         span,
248         vec![],
249         None,
250     )
251 }
252
253 pub struct DropShimElaborator<'a, 'tcx> {
254     pub body: &'a Body<'tcx>,
255     pub patch: MirPatch<'tcx>,
256     pub tcx: TyCtxt<'tcx>,
257     pub param_env: ty::ParamEnv<'tcx>,
258 }
259
260 impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
261     fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
262         Ok(())
263     }
264 }
265
266 impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
267     type Path = ();
268
269     fn patch(&mut self) -> &mut MirPatch<'tcx> {
270         &mut self.patch
271     }
272     fn body(&self) -> &'a Body<'tcx> {
273         self.body
274     }
275     fn tcx(&self) -> TyCtxt<'tcx> {
276         self.tcx
277     }
278     fn param_env(&self) -> ty::ParamEnv<'tcx> {
279         self.param_env
280     }
281
282     fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
283         match mode {
284             DropFlagMode::Shallow => {
285                 // Drops for the contained fields are "shallow" and "static" - they will simply call
286                 // the field's own drop glue.
287                 DropStyle::Static
288             }
289             DropFlagMode::Deep => {
290                 // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
291                 // dropping each field contained in the value.
292                 DropStyle::Open
293             }
294         }
295     }
296
297     fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
298         None
299     }
300
301     fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {}
302
303     fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
304         None
305     }
306     fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
307         None
308     }
309     fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
310         Some(())
311     }
312     fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
313         None
314     }
315 }
316
317 /// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
318 fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
319     debug!("build_clone_shim(def_id={:?})", def_id);
320
321     let param_env = tcx.param_env(def_id);
322
323     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
324     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
325
326     let dest = Place::return_place();
327     let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
328
329     match self_ty.kind {
330         _ if is_copy => builder.copy_shim(),
331         ty::Array(ty, len) => {
332             let len = len.eval_usize(tcx, param_env);
333             builder.array_shim(dest, src, ty, len)
334         }
335         ty::Closure(_, substs) => {
336             builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
337         }
338         ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
339         _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
340     };
341
342     builder.into_mir()
343 }
344
345 struct CloneShimBuilder<'tcx> {
346     tcx: TyCtxt<'tcx>,
347     def_id: DefId,
348     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
349     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
350     span: Span,
351     sig: ty::FnSig<'tcx>,
352 }
353
354 impl CloneShimBuilder<'tcx> {
355     fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
356         // we must subst the self_ty because it's
357         // otherwise going to be TySelf and we can't index
358         // or access fields of a Place of type TySelf.
359         let substs = tcx.mk_substs_trait(self_ty, &[]);
360         let sig = tcx.fn_sig(def_id).subst(tcx, substs);
361         let sig = tcx.erase_late_bound_regions(&sig);
362         let span = tcx.def_span(def_id);
363
364         CloneShimBuilder {
365             tcx,
366             def_id,
367             local_decls: local_decls_for_sig(&sig, span),
368             blocks: IndexVec::new(),
369             span,
370             sig,
371         }
372     }
373
374     fn into_mir(self) -> Body<'tcx> {
375         new_body(self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
376     }
377
378     fn source_info(&self) -> SourceInfo {
379         SourceInfo::outermost(self.span)
380     }
381
382     fn block(
383         &mut self,
384         statements: Vec<Statement<'tcx>>,
385         kind: TerminatorKind<'tcx>,
386         is_cleanup: bool,
387     ) -> BasicBlock {
388         let source_info = self.source_info();
389         self.blocks.push(BasicBlockData {
390             statements,
391             terminator: Some(Terminator { source_info, kind }),
392             is_cleanup,
393         })
394     }
395
396     /// Gives the index of an upcoming BasicBlock, with an offset.
397     /// offset=0 will give you the index of the next BasicBlock,
398     /// offset=1 will give the index of the next-to-next block,
399     /// offset=-1 will give you the index of the last-created block
400     fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
401         BasicBlock::new(self.blocks.len() + offset)
402     }
403
404     fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
405         Statement { source_info: self.source_info(), kind }
406     }
407
408     fn copy_shim(&mut self) {
409         let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
410         let ret_statement = self.make_statement(StatementKind::Assign(box (
411             Place::return_place(),
412             Rvalue::Use(Operand::Copy(rcvr)),
413         )));
414         self.block(vec![ret_statement], TerminatorKind::Return, false);
415     }
416
417     fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
418         let span = self.span;
419         let mut local = LocalDecl::new(ty, span);
420         if mutability == Mutability::Not {
421             local = local.immutable();
422         }
423         Place::from(self.local_decls.push(local))
424     }
425
426     fn make_clone_call(
427         &mut self,
428         dest: Place<'tcx>,
429         src: Place<'tcx>,
430         ty: Ty<'tcx>,
431         next: BasicBlock,
432         cleanup: BasicBlock,
433     ) {
434         let tcx = self.tcx;
435
436         let substs = tcx.mk_substs_trait(ty, &[]);
437
438         // `func == Clone::clone(&ty) -> ty`
439         let func_ty = tcx.mk_fn_def(self.def_id, substs);
440         let func = Operand::Constant(box Constant {
441             span: self.span,
442             user_ty: None,
443             literal: ty::Const::zero_sized(tcx, func_ty),
444         });
445
446         let ref_loc = self.make_place(
447             Mutability::Not,
448             tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }),
449         );
450
451         // `let ref_loc: &ty = &src;`
452         let statement = self.make_statement(StatementKind::Assign(box (
453             ref_loc,
454             Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
455         )));
456
457         // `let loc = Clone::clone(ref_loc);`
458         self.block(
459             vec![statement],
460             TerminatorKind::Call {
461                 func,
462                 args: vec![Operand::Move(ref_loc)],
463                 destination: Some((dest, next)),
464                 cleanup: Some(cleanup),
465                 from_hir_call: true,
466                 fn_span: self.span,
467             },
468             false,
469         );
470     }
471
472     fn loop_header(
473         &mut self,
474         beg: Place<'tcx>,
475         end: Place<'tcx>,
476         loop_body: BasicBlock,
477         loop_end: BasicBlock,
478         is_cleanup: bool,
479     ) {
480         let tcx = self.tcx;
481
482         let cond = self.make_place(Mutability::Mut, tcx.types.bool);
483         let compute_cond = self.make_statement(StatementKind::Assign(box (
484             cond,
485             Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)),
486         )));
487
488         // `if end != beg { goto loop_body; } else { goto loop_end; }`
489         self.block(
490             vec![compute_cond],
491             TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
492             is_cleanup,
493         );
494     }
495
496     fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
497         box Constant {
498             span: self.span,
499             user_ty: None,
500             literal: ty::Const::from_usize(self.tcx, value),
501         }
502     }
503
504     fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
505         let tcx = self.tcx;
506         let span = self.span;
507
508         let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
509         let end = self.make_place(Mutability::Not, tcx.types.usize);
510
511         // BB #0
512         // `let mut beg = 0;`
513         // `let end = len;`
514         // `goto #1;`
515         let inits = vec![
516             self.make_statement(StatementKind::Assign(box (
517                 Place::from(beg),
518                 Rvalue::Use(Operand::Constant(self.make_usize(0))),
519             ))),
520             self.make_statement(StatementKind::Assign(box (
521                 end,
522                 Rvalue::Use(Operand::Constant(self.make_usize(len))),
523             ))),
524         ];
525         self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
526
527         // BB #1: loop {
528         //     BB #2;
529         //     BB #3;
530         // }
531         // BB #4;
532         self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
533
534         // BB #2
535         // `dest[i] = Clone::clone(src[beg])`;
536         // Goto #3 if ok, #5 if unwinding happens.
537         let dest_field = self.tcx.mk_place_index(dest, beg);
538         let src_field = self.tcx.mk_place_index(src, beg);
539         self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
540
541         // BB #3
542         // `beg = beg + 1;`
543         // `goto #1`;
544         let statements = vec![self.make_statement(StatementKind::Assign(box (
545             Place::from(beg),
546             Rvalue::BinaryOp(
547                 BinOp::Add,
548                 Operand::Copy(Place::from(beg)),
549                 Operand::Constant(self.make_usize(1)),
550             ),
551         )))];
552         self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
553
554         // BB #4
555         // `return dest;`
556         self.block(vec![], TerminatorKind::Return, false);
557
558         // BB #5 (cleanup)
559         // `let end = beg;`
560         // `let mut beg = 0;`
561         // goto #6;
562         let end = beg;
563         let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
564         let init = self.make_statement(StatementKind::Assign(box (
565             Place::from(beg),
566             Rvalue::Use(Operand::Constant(self.make_usize(0))),
567         )));
568         self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
569
570         // BB #6 (cleanup): loop {
571         //     BB #7;
572         //     BB #8;
573         // }
574         // BB #9;
575         self.loop_header(
576             Place::from(beg),
577             Place::from(end),
578             BasicBlock::new(7),
579             BasicBlock::new(9),
580             true,
581         );
582
583         // BB #7 (cleanup)
584         // `drop(dest[beg])`;
585         self.block(
586             vec![],
587             TerminatorKind::Drop {
588                 location: self.tcx.mk_place_index(dest, beg),
589                 target: BasicBlock::new(8),
590                 unwind: None,
591             },
592             true,
593         );
594
595         // BB #8 (cleanup)
596         // `beg = beg + 1;`
597         // `goto #6;`
598         let statement = self.make_statement(StatementKind::Assign(box (
599             Place::from(beg),
600             Rvalue::BinaryOp(
601                 BinOp::Add,
602                 Operand::Copy(Place::from(beg)),
603                 Operand::Constant(self.make_usize(1)),
604             ),
605         )));
606         self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
607
608         // BB #9 (resume)
609         self.block(vec![], TerminatorKind::Resume, true);
610     }
611
612     fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
613     where
614         I: Iterator<Item = Ty<'tcx>>,
615     {
616         let mut previous_field = None;
617         for (i, ity) in tys.enumerate() {
618             let field = Field::new(i);
619             let src_field = self.tcx.mk_place_field(src, field, ity);
620
621             let dest_field = self.tcx.mk_place_field(dest, field, ity);
622
623             // #(2i + 1) is the cleanup block for the previous clone operation
624             let cleanup_block = self.block_index_offset(1);
625             // #(2i + 2) is the next cloning block
626             // (or the Return terminator if this is the last block)
627             let next_block = self.block_index_offset(2);
628
629             // BB #(2i)
630             // `dest.i = Clone::clone(&src.i);`
631             // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
632             self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block);
633
634             // BB #(2i + 1) (cleanup)
635             if let Some((previous_field, previous_cleanup)) = previous_field.take() {
636                 // Drop previous field and goto previous cleanup block.
637                 self.block(
638                     vec![],
639                     TerminatorKind::Drop {
640                         location: previous_field,
641                         target: previous_cleanup,
642                         unwind: None,
643                     },
644                     true,
645                 );
646             } else {
647                 // Nothing to drop, just resume.
648                 self.block(vec![], TerminatorKind::Resume, true);
649             }
650
651             previous_field = Some((dest_field, cleanup_block));
652         }
653
654         self.block(vec![], TerminatorKind::Return, false);
655     }
656 }
657
658 /// Builds a "call" shim for `instance`. The shim calls the
659 /// function specified by `call_kind`, first adjusting its first
660 /// argument according to `rcvr_adjustment`.
661 ///
662 /// If `untuple_args` is a vec of types, the second argument of the
663 /// function will be untupled as these types.
664 fn build_call_shim<'tcx>(
665     tcx: TyCtxt<'tcx>,
666     instance: ty::InstanceDef<'tcx>,
667     rcvr_adjustment: Option<Adjustment>,
668     call_kind: CallKind,
669     untuple_args: Option<&[Ty<'tcx>]>,
670 ) -> Body<'tcx> {
671     debug!(
672         "build_call_shim(instance={:?}, rcvr_adjustment={:?}, \
673             call_kind={:?}, untuple_args={:?})",
674         instance, rcvr_adjustment, call_kind, untuple_args
675     );
676
677     let def_id = instance.def_id();
678     let sig = tcx.fn_sig(def_id);
679     let mut sig = tcx.erase_late_bound_regions(&sig);
680
681     // FIXME(eddyb) avoid having this snippet both here and in
682     // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
683     if let ty::InstanceDef::VtableShim(..) = instance {
684         // Modify fn(self, ...) to fn(self: *mut Self, ...)
685         let mut inputs_and_output = sig.inputs_and_output.to_vec();
686         let self_arg = &mut inputs_and_output[0];
687         debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
688         *self_arg = tcx.mk_mut_ptr(*self_arg);
689         sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
690     }
691
692     let span = tcx.def_span(def_id);
693
694     debug!("build_call_shim: sig={:?}", sig);
695
696     let mut local_decls = local_decls_for_sig(&sig, span);
697     let source_info = SourceInfo::outermost(span);
698
699     let rcvr_place = || {
700         assert!(rcvr_adjustment.is_some());
701         Place::from(Local::new(1 + 0))
702     };
703     let mut statements = vec![];
704
705     let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
706         Adjustment::Identity => Operand::Move(rcvr_place()),
707         Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut`
708         Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
709         Adjustment::RefMut => {
710             // let rcvr = &mut rcvr;
711             let ref_rcvr = local_decls.push(
712                 LocalDecl::new(
713                     tcx.mk_ref(
714                         tcx.lifetimes.re_erased,
715                         ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
716                     ),
717                     span,
718                 )
719                 .immutable(),
720             );
721             let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false };
722             statements.push(Statement {
723                 source_info,
724                 kind: StatementKind::Assign(box (
725                     Place::from(ref_rcvr),
726                     Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
727                 )),
728             });
729             Operand::Move(Place::from(ref_rcvr))
730         }
731     });
732
733     let (callee, mut args) = match call_kind {
734         CallKind::Indirect => (rcvr.unwrap(), vec![]),
735         CallKind::Direct(def_id) => {
736             let ty = tcx.type_of(def_id);
737             (
738                 Operand::Constant(box Constant {
739                     span,
740                     user_ty: None,
741                     literal: ty::Const::zero_sized(tcx, ty),
742                 }),
743                 rcvr.into_iter().collect::<Vec<_>>(),
744             )
745         }
746     };
747
748     let mut arg_range = 0..sig.inputs().len();
749
750     // Take the `self` ("receiver") argument out of the range (it's adjusted above).
751     if rcvr_adjustment.is_some() {
752         arg_range.start += 1;
753     }
754
755     // Take the last argument, if we need to untuple it (handled below).
756     if untuple_args.is_some() {
757         arg_range.end -= 1;
758     }
759
760     // Pass all of the non-special arguments directly.
761     args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
762
763     // Untuple the last argument, if we have to.
764     if let Some(untuple_args) = untuple_args {
765         let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
766         args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
767             Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity))
768         }));
769     }
770
771     let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
772     let mut blocks = IndexVec::with_capacity(n_blocks);
773     let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
774         blocks.push(BasicBlockData {
775             statements,
776             terminator: Some(Terminator { source_info, kind }),
777             is_cleanup,
778         })
779     };
780
781     // BB #0
782     block(
783         &mut blocks,
784         statements,
785         TerminatorKind::Call {
786             func: callee,
787             args,
788             destination: Some((Place::return_place(), BasicBlock::new(1))),
789             cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
790                 Some(BasicBlock::new(3))
791             } else {
792                 None
793             },
794             from_hir_call: true,
795             fn_span: span,
796         },
797         false,
798     );
799
800     if let Some(Adjustment::RefMut) = rcvr_adjustment {
801         // BB #1 - drop for Self
802         block(
803             &mut blocks,
804             vec![],
805             TerminatorKind::Drop {
806                 location: rcvr_place(),
807                 target: BasicBlock::new(2),
808                 unwind: None,
809             },
810             false,
811         );
812     }
813     // BB #1/#2 - return
814     block(&mut blocks, vec![], TerminatorKind::Return, false);
815     if let Some(Adjustment::RefMut) = rcvr_adjustment {
816         // BB #3 - drop if closure panics
817         block(
818             &mut blocks,
819             vec![],
820             TerminatorKind::Drop {
821                 location: rcvr_place(),
822                 target: BasicBlock::new(4),
823                 unwind: None,
824             },
825             true,
826         );
827
828         // BB #4 - resume
829         block(&mut blocks, vec![], TerminatorKind::Resume, true);
830     }
831
832     let mut body = new_body(blocks, local_decls, sig.inputs().len(), span);
833
834     if let Abi::RustCall = sig.abi {
835         body.spread_arg = Some(Local::new(sig.inputs().len()));
836     }
837
838     body
839 }
840
841 pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
842     debug_assert!(tcx.is_constructor(ctor_id));
843
844     let span =
845         tcx.hir().span_if_local(ctor_id).unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
846
847     let param_env = tcx.param_env(ctor_id);
848
849     // Normalize the sig.
850     let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature");
851     let sig = tcx.normalize_erasing_regions(param_env, sig);
852
853     let (adt_def, substs) = match sig.output().kind {
854         ty::Adt(adt_def, substs) => (adt_def, substs),
855         _ => bug!("unexpected type for ADT ctor {:?}", sig.output()),
856     };
857
858     debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
859
860     let local_decls = local_decls_for_sig(&sig, span);
861
862     let source_info = SourceInfo::outermost(span);
863
864     let variant_index = if adt_def.is_enum() {
865         adt_def.variant_index_with_ctor_id(ctor_id)
866     } else {
867         VariantIdx::new(0)
868     };
869
870     // Generate the following MIR:
871     //
872     // (return as Variant).field0 = arg0;
873     // (return as Variant).field1 = arg1;
874     //
875     // return;
876     debug!("build_ctor: variant_index={:?}", variant_index);
877
878     let statements = expand_aggregate(
879         Place::return_place(),
880         adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| {
881             (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs))
882         }),
883         AggregateKind::Adt(adt_def, variant_index, substs, None, None),
884         source_info,
885         tcx,
886     )
887     .collect();
888
889     let start_block = BasicBlockData {
890         statements,
891         terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
892         is_cleanup: false,
893     };
894
895     let body =
896         new_body(IndexVec::from_elem_n(start_block, 1), local_decls, sig.inputs().len(), span);
897
898     crate::util::dump_mir(
899         tcx,
900         None,
901         "mir_map",
902         &0,
903         crate::transform::MirSource::item(ctor_id),
904         &body,
905         |_, _| Ok(()),
906     );
907
908     body
909 }