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