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