]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/shim.rs
Rollup merge of #66612 - Nadrieril:or-patterns-initial, r=varkor
[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     debug!("make_shim({:?}) = {:?}", instance, result);
127
128     tcx.arena.alloc(result)
129 }
130
131 #[derive(Copy, Clone, Debug, PartialEq)]
132 enum Adjustment {
133     Identity,
134     Deref,
135     DerefMove,
136     RefMut,
137 }
138
139 #[derive(Copy, Clone, Debug, PartialEq)]
140 enum CallKind {
141     Indirect,
142     Direct(DefId),
143 }
144
145 fn temp_decl(mutability: Mutability, ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
146     let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
147     LocalDecl {
148         mutability,
149         ty,
150         user_ty: UserTypeProjections::none(),
151         source_info,
152         internal: false,
153         local_info: LocalInfo::Other,
154         is_block_tail: None,
155     }
156 }
157
158 fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span)
159     -> IndexVec<Local, LocalDecl<'tcx>>
160 {
161     iter::once(temp_decl(Mutability::Mut, sig.output(), span))
162         .chain(sig.inputs().iter().map(
163             |ity| temp_decl(Mutability::Not, ity, span)))
164         .collect()
165 }
166
167 fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
168     debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
169
170     // Check if this is a generator, if so, return the drop glue for it
171     if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty {
172         let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap();
173         return body.subst(tcx, substs);
174     }
175
176     let substs = if let Some(ty) = ty {
177         tcx.intern_substs(&[ty.into()])
178     } else {
179         InternalSubsts::identity_for_item(tcx, def_id)
180     };
181     let sig = tcx.fn_sig(def_id).subst(tcx, substs);
182     let sig = tcx.erase_late_bound_regions(&sig);
183     let span = tcx.def_span(def_id);
184
185     let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
186
187     let return_block = BasicBlock::new(1);
188     let mut blocks = IndexVec::with_capacity(2);
189     let block = |blocks: &mut IndexVec<_, _>, kind| {
190         blocks.push(BasicBlockData {
191             statements: vec![],
192             terminator: Some(Terminator { source_info, kind }),
193             is_cleanup: false
194         })
195     };
196     block(&mut blocks, TerminatorKind::Goto { target: return_block });
197     block(&mut blocks, TerminatorKind::Return);
198
199     let mut body = new_body(
200         blocks,
201         IndexVec::from_elem_n(
202             SourceScopeData { span, parent_scope: None }, 1
203         ),
204         local_decls_for_sig(&sig, span),
205         sig.inputs().len(),
206         span);
207
208     if let Some(..) = ty {
209         // The first argument (index 0), but add 1 for the return value.
210         let dropee_ptr = Place::from(Local::new(1+0));
211         if tcx.sess.opts.debugging_opts.mir_emit_retag {
212             // Function arguments should be retagged, and we make this one raw.
213             body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
214                 source_info,
215                 kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
216             });
217         }
218         let patch = {
219             let param_env = tcx.param_env(def_id).with_reveal_all();
220             let mut elaborator = DropShimElaborator {
221                 body: &body,
222                 patch: MirPatch::new(&body),
223                 tcx,
224                 param_env
225             };
226             let dropee = tcx.mk_place_deref(dropee_ptr);
227             let resume_block = elaborator.patch.resume_block();
228             elaborate_drops::elaborate_drop(
229                 &mut elaborator,
230                 source_info,
231                 &dropee,
232                 (),
233                 return_block,
234                 elaborate_drops::Unwind::To(resume_block),
235                 START_BLOCK
236             );
237             elaborator.patch
238         };
239         patch.apply(&mut body);
240     }
241
242     body
243 }
244
245 fn new_body<'tcx>(
246     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
247     source_scopes: IndexVec<SourceScope, SourceScopeData>,
248     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
249     arg_count: usize,
250     span: Span,
251 ) -> Body<'tcx> {
252     Body::new(
253         basic_blocks,
254         source_scopes,
255         ClearCrossCrate::Clear,
256         local_decls,
257         IndexVec::new(),
258         arg_count,
259         vec![],
260         span,
261         vec![],
262         None,
263     )
264 }
265
266 pub struct DropShimElaborator<'a, 'tcx> {
267     pub body: &'a Body<'tcx>,
268     pub patch: MirPatch<'tcx>,
269     pub tcx: TyCtxt<'tcx>,
270     pub param_env: ty::ParamEnv<'tcx>,
271 }
272
273 impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
274     fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
275         Ok(())
276     }
277 }
278
279 impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
280     type Path = ();
281
282     fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch }
283     fn body(&self) -> &'a Body<'tcx> { self.body }
284     fn tcx(&self) -> TyCtxt<'tcx> {
285         self.tcx
286         }
287     fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
288
289     fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
290         if let DropFlagMode::Shallow = mode {
291             DropStyle::Static
292         } else {
293             DropStyle::Open
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
304     fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
305         None
306     }
307     fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
308         None
309     }
310     fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
311         Some(())
312     }
313     fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
314         None
315     }
316 }
317
318 /// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
319 fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
320     debug!("build_clone_shim(def_id={:?})", def_id);
321
322     let param_env = tcx.param_env(def_id);
323
324     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
325     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
326
327     let dest = Place::return_place();
328     let src = tcx.mk_place_deref(Place::from(Local::new(1+0)));
329
330     match self_ty.kind {
331         _ if is_copy => builder.copy_shim(),
332         ty::Array(ty, len) => {
333             let len = len.eval_usize(tcx, param_env);
334             builder.array_shim(dest, src, ty, len)
335         }
336         ty::Closure(def_id, substs) => {
337             builder.tuple_like_shim(
338                 dest, src,
339                 substs.as_closure().upvar_tys(def_id, tcx)
340             )
341         }
342         ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
343         _ => {
344             bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
345         }
346     };
347
348     builder.into_mir()
349 }
350
351 struct CloneShimBuilder<'tcx> {
352     tcx: TyCtxt<'tcx>,
353     def_id: DefId,
354     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
355     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
356     span: Span,
357     sig: ty::FnSig<'tcx>,
358 }
359
360 impl CloneShimBuilder<'tcx> {
361     fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
362         // we must subst the self_ty because it's
363         // otherwise going to be TySelf and we can't index
364         // or access fields of a Place of type TySelf.
365         let substs = tcx.mk_substs_trait(self_ty, &[]);
366         let sig = tcx.fn_sig(def_id).subst(tcx, substs);
367         let sig = tcx.erase_late_bound_regions(&sig);
368         let span = tcx.def_span(def_id);
369
370         CloneShimBuilder {
371             tcx,
372             def_id,
373             local_decls: local_decls_for_sig(&sig, span),
374             blocks: IndexVec::new(),
375             span,
376             sig,
377         }
378     }
379
380     fn into_mir(self) -> Body<'tcx> {
381         new_body(
382             self.blocks,
383             IndexVec::from_elem_n(
384                 SourceScopeData { span: self.span, parent_scope: None }, 1
385             ),
386             self.local_decls,
387             self.sig.inputs().len(),
388             self.span,
389         )
390     }
391
392     fn source_info(&self) -> SourceInfo {
393         SourceInfo { span: self.span, scope: OUTERMOST_SOURCE_SCOPE }
394     }
395
396     fn block(
397         &mut self,
398         statements: Vec<Statement<'tcx>>,
399         kind: TerminatorKind<'tcx>,
400         is_cleanup: bool
401     ) -> BasicBlock {
402         let source_info = self.source_info();
403         self.blocks.push(BasicBlockData {
404             statements,
405             terminator: Some(Terminator { source_info, kind }),
406             is_cleanup,
407         })
408     }
409
410     /// Gives the index of an upcoming BasicBlock, with an offset.
411     /// offset=0 will give you the index of the next BasicBlock,
412     /// offset=1 will give the index of the next-to-next block,
413     /// offset=-1 will give you the index of the last-created block
414     fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
415         BasicBlock::new(self.blocks.len() + offset)
416     }
417
418     fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
419         Statement {
420             source_info: self.source_info(),
421             kind,
422         }
423     }
424
425     fn copy_shim(&mut self) {
426         let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1+0)));
427         let ret_statement = self.make_statement(
428             StatementKind::Assign(
429                 box(
430                     Place::return_place(),
431                     Rvalue::Use(Operand::Copy(rcvr))
432                 )
433             )
434         );
435         self.block(vec![ret_statement], TerminatorKind::Return, false);
436     }
437
438     fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
439         let span = self.span;
440         Place::from(self.local_decls.push(temp_decl(mutability, ty, span)))
441     }
442
443     fn make_clone_call(
444         &mut self,
445         dest: Place<'tcx>,
446         src: Place<'tcx>,
447         ty: Ty<'tcx>,
448         next: BasicBlock,
449         cleanup: BasicBlock
450     ) {
451         let tcx = self.tcx;
452
453         let substs = tcx.mk_substs_trait(ty, &[]);
454
455         // `func == Clone::clone(&ty) -> ty`
456         let func_ty = tcx.mk_fn_def(self.def_id, substs);
457         let func = Operand::Constant(box Constant {
458             span: self.span,
459             user_ty: None,
460             literal: ty::Const::zero_sized(tcx, func_ty),
461         });
462
463         let ref_loc = self.make_place(
464             Mutability::Not,
465             tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut {
466                 ty,
467                 mutbl: hir::Mutability::Immutable,
468             })
469         );
470
471         // `let ref_loc: &ty = &src;`
472         let statement = self.make_statement(
473             StatementKind::Assign(
474                 box(
475                     ref_loc.clone(),
476                     Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
477                 )
478             )
479         );
480
481         // `let loc = Clone::clone(ref_loc);`
482         self.block(vec![statement], TerminatorKind::Call {
483             func,
484             args: vec![Operand::Move(ref_loc)],
485             destination: Some((dest, next)),
486             cleanup: Some(cleanup),
487             from_hir_call: true,
488         }, false);
489     }
490
491     fn loop_header(
492         &mut self,
493         beg: Place<'tcx>,
494         end: Place<'tcx>,
495         loop_body: BasicBlock,
496         loop_end: BasicBlock,
497         is_cleanup: bool
498     ) {
499         let tcx = self.tcx;
500
501         let cond = self.make_place(Mutability::Mut, tcx.types.bool);
502         let compute_cond = self.make_statement(
503             StatementKind::Assign(
504                 box(
505                     cond.clone(),
506                     Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
507                 )
508             )
509         );
510
511         // `if end != beg { goto loop_body; } else { goto loop_end; }`
512         self.block(
513             vec![compute_cond],
514             TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
515             is_cleanup
516         );
517     }
518
519     fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
520         box Constant {
521             span: self.span,
522             user_ty: None,
523             literal: ty::Const::from_usize(self.tcx, value),
524         }
525     }
526
527     fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
528         let tcx = self.tcx;
529         let span = self.span;
530
531         let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
532         let end = self.make_place(Mutability::Not, tcx.types.usize);
533
534         // BB #0
535         // `let mut beg = 0;`
536         // `let end = len;`
537         // `goto #1;`
538         let inits = vec![
539             self.make_statement(
540                 StatementKind::Assign(
541                     box(
542                         Place::from(beg),
543                         Rvalue::Use(Operand::Constant(self.make_usize(0)))
544                     )
545                 )
546             ),
547             self.make_statement(
548                 StatementKind::Assign(
549                     box(
550                         end.clone(),
551                         Rvalue::Use(Operand::Constant(self.make_usize(len)))
552                     )
553                 )
554             )
555         ];
556         self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
557
558         // BB #1: loop {
559         //     BB #2;
560         //     BB #3;
561         // }
562         // BB #4;
563         self.loop_header(Place::from(beg),
564                          end,
565                          BasicBlock::new(2),
566                          BasicBlock::new(4),
567                          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 = self.tcx.mk_place_index(dest.clone(), beg);
573         let src_field = self.tcx.mk_place_index(src, 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                     box(
584                         Place::from(beg),
585                         Rvalue::BinaryOp(
586                             BinOp::Add,
587                             Operand::Copy(Place::from(beg)),
588                             Operand::Constant(self.make_usize(1))
589                         )
590                     )
591                 )
592             )
593         ];
594         self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
595
596         // BB #4
597         // `return dest;`
598         self.block(vec![], TerminatorKind::Return, false);
599
600         // BB #5 (cleanup)
601         // `let end = beg;`
602         // `let mut beg = 0;`
603         // goto #6;
604         let end = beg;
605         let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
606         let init = self.make_statement(
607             StatementKind::Assign(
608                 box(
609                     Place::from(beg),
610                     Rvalue::Use(Operand::Constant(self.make_usize(0)))
611                 )
612             )
613         );
614         self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
615
616         // BB #6 (cleanup): loop {
617         //     BB #7;
618         //     BB #8;
619         // }
620         // BB #9;
621         self.loop_header(Place::from(beg), Place::from(end),
622                          BasicBlock::new(7), BasicBlock::new(9), true);
623
624         // BB #7 (cleanup)
625         // `drop(dest[beg])`;
626         self.block(vec![], TerminatorKind::Drop {
627             location: self.tcx.mk_place_index(dest, beg),
628             target: BasicBlock::new(8),
629             unwind: None,
630         }, true);
631
632         // BB #8 (cleanup)
633         // `beg = beg + 1;`
634         // `goto #6;`
635         let statement = self.make_statement(
636             StatementKind::Assign(
637                 box(
638                     Place::from(beg),
639                     Rvalue::BinaryOp(
640                         BinOp::Add,
641                         Operand::Copy(Place::from(beg)),
642                         Operand::Constant(self.make_usize(1))
643                     )
644                 )
645             )
646         );
647         self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
648
649         // BB #9 (resume)
650         self.block(vec![], TerminatorKind::Resume, true);
651     }
652
653     fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>,
654                           src: Place<'tcx>, tys: I)
655             where I: Iterator<Item = Ty<'tcx>> {
656         let mut previous_field = None;
657         for (i, ity) in tys.enumerate() {
658             let field = Field::new(i);
659             let src_field = self.tcx.mk_place_field(src.clone(), field, ity);
660
661             let dest_field = self.tcx.mk_place_field(dest.clone(), field, ity);
662
663             // #(2i + 1) is the cleanup block for the previous clone operation
664             let cleanup_block = self.block_index_offset(1);
665             // #(2i + 2) is the next cloning block
666             // (or the Return terminator if this is the last block)
667             let next_block = self.block_index_offset(2);
668
669             // BB #(2i)
670             // `dest.i = Clone::clone(&src.i);`
671             // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
672             self.make_clone_call(
673                 dest_field.clone(),
674                 src_field,
675                 ity,
676                 next_block,
677                 cleanup_block,
678             );
679
680             // BB #(2i + 1) (cleanup)
681             if let Some((previous_field, previous_cleanup)) = previous_field.take() {
682                 // Drop previous field and goto previous cleanup block.
683                 self.block(vec![], TerminatorKind::Drop {
684                     location: previous_field,
685                     target: previous_cleanup,
686                     unwind: None,
687                 }, true);
688             } else {
689                 // Nothing to drop, just resume.
690                 self.block(vec![], TerminatorKind::Resume, true);
691             }
692
693             previous_field = Some((dest_field, cleanup_block));
694         }
695
696         self.block(vec![], TerminatorKind::Return, false);
697     }
698 }
699
700 /// Builds a "call" shim for `def_id`. The shim calls the
701 /// function specified by `call_kind`, first adjusting its first
702 /// argument according to `rcvr_adjustment`.
703 ///
704 /// If `untuple_args` is a vec of types, the second argument of the
705 /// function will be untupled as these types.
706 fn build_call_shim<'tcx>(
707     tcx: TyCtxt<'tcx>,
708     def_id: DefId,
709     rcvr_adjustment: Adjustment,
710     call_kind: CallKind,
711     untuple_args: Option<&[Ty<'tcx>]>,
712 ) -> Body<'tcx> {
713     debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
714             call_kind={:?}, untuple_args={:?})",
715            def_id, rcvr_adjustment, call_kind, untuple_args);
716
717     let sig = tcx.fn_sig(def_id);
718     let sig = tcx.erase_late_bound_regions(&sig);
719     let span = tcx.def_span(def_id);
720
721     debug!("build_call_shim: sig={:?}", sig);
722
723     let mut local_decls = local_decls_for_sig(&sig, span);
724     let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
725
726     let rcvr_arg = Local::new(1+0);
727     let rcvr_l = Place::from(rcvr_arg);
728     let mut statements = vec![];
729
730     let rcvr = match rcvr_adjustment {
731         Adjustment::Identity => Operand::Move(rcvr_l),
732         Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
733         Adjustment::DerefMove => {
734             // fn(Self, ...) -> fn(*mut Self, ...)
735             let arg_ty = local_decls[rcvr_arg].ty;
736             debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param);
737             local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
738
739             Operand::Move(tcx.mk_place_deref(rcvr_l))
740         }
741         Adjustment::RefMut => {
742             // let rcvr = &mut rcvr;
743             let ref_rcvr = local_decls.push(temp_decl(
744                 Mutability::Not,
745                 tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut {
746                     ty: sig.inputs()[0],
747                     mutbl: hir::Mutability::Mutable
748                 }),
749                 span
750             ));
751             let borrow_kind = BorrowKind::Mut {
752                 allow_two_phase_borrow: false,
753             };
754             statements.push(Statement {
755                 source_info,
756                 kind: StatementKind::Assign(
757                     box(
758                         Place::from(ref_rcvr),
759                         Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
760                     )
761                 )
762             });
763             Operand::Move(Place::from(ref_rcvr))
764         }
765     };
766
767     let (callee, mut args) = match call_kind {
768         CallKind::Indirect => (rcvr, vec![]),
769         CallKind::Direct(def_id) => {
770             let ty = tcx.type_of(def_id);
771             (Operand::Constant(box Constant {
772                 span,
773                 user_ty: None,
774                 literal: ty::Const::zero_sized(tcx, ty),
775              }),
776              vec![rcvr])
777         }
778     };
779
780     if let Some(untuple_args) = untuple_args {
781         args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
782             let arg_place = Place::from(Local::new(1+1));
783             Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
784         }));
785     } else {
786         args.extend((1..sig.inputs().len()).map(|i| {
787             Operand::Move(Place::from(Local::new(1+i)))
788         }));
789     }
790
791     let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 };
792     let mut blocks = IndexVec::with_capacity(n_blocks);
793     let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
794         blocks.push(BasicBlockData {
795             statements,
796             terminator: Some(Terminator { source_info, kind }),
797             is_cleanup
798         })
799     };
800
801     // BB #0
802     block(&mut blocks, statements, TerminatorKind::Call {
803         func: callee,
804         args,
805         destination: Some((Place::return_place(),
806                            BasicBlock::new(1))),
807         cleanup: if let Adjustment::RefMut = rcvr_adjustment {
808             Some(BasicBlock::new(3))
809         } else {
810             None
811         },
812         from_hir_call: true,
813     }, false);
814
815     if let Adjustment::RefMut = rcvr_adjustment {
816         // BB #1 - drop for Self
817         block(&mut blocks, vec![], TerminatorKind::Drop {
818             location: Place::from(rcvr_arg),
819             target: BasicBlock::new(2),
820             unwind: None
821         }, false);
822     }
823     // BB #1/#2 - return
824     block(&mut blocks, vec![], TerminatorKind::Return, false);
825     if let Adjustment::RefMut = rcvr_adjustment {
826         // BB #3 - drop if closure panics
827         block(&mut blocks, vec![], TerminatorKind::Drop {
828             location: Place::from(rcvr_arg),
829             target: BasicBlock::new(4),
830             unwind: None
831         }, true);
832
833         // BB #4 - resume
834         block(&mut blocks, vec![], TerminatorKind::Resume, true);
835     }
836
837     let mut body = new_body(
838         blocks,
839         IndexVec::from_elem_n(
840             SourceScopeData { span, parent_scope: None }, 1
841         ),
842         local_decls,
843         sig.inputs().len(),
844         span,
845     );
846
847     if let Abi::RustCall = sig.abi {
848         body.spread_arg = Some(Local::new(sig.inputs().len()));
849     }
850     body
851 }
852
853 pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
854     debug_assert!(tcx.is_constructor(ctor_id));
855
856     let span = tcx.hir().span_if_local(ctor_id)
857         .unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
858
859     let param_env = tcx.param_env(ctor_id);
860
861     // Normalize the sig.
862     let sig = tcx.fn_sig(ctor_id)
863         .no_bound_vars()
864         .expect("LBR in ADT constructor signature");
865     let sig = tcx.normalize_erasing_regions(param_env, sig);
866
867     let (adt_def, substs) = match sig.output().kind {
868         ty::Adt(adt_def, substs) => (adt_def, substs),
869         _ => bug!("unexpected type for ADT ctor {:?}", sig.output())
870     };
871
872     debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
873
874     let local_decls = local_decls_for_sig(&sig, span);
875
876     let source_info = SourceInfo {
877         span,
878         scope: OUTERMOST_SOURCE_SCOPE
879     };
880
881     let variant_index = if adt_def.is_enum() {
882         adt_def.variant_index_with_ctor_id(ctor_id)
883     } else {
884         VariantIdx::new(0)
885     };
886
887     // Generate the following MIR:
888     //
889     // (return as Variant).field0 = arg0;
890     // (return as Variant).field1 = arg1;
891     //
892     // return;
893     debug!("build_ctor: variant_index={:?}", variant_index);
894
895     let statements = expand_aggregate(
896         Place::return_place(),
897         adt_def
898             .variants[variant_index]
899             .fields
900             .iter()
901             .enumerate()
902             .map(|(idx, field_def)| (
903                 Operand::Move(Place::from(Local::new(idx + 1))),
904                 field_def.ty(tcx, substs),
905             )),
906         AggregateKind::Adt(adt_def, variant_index, substs, None, None),
907         source_info,
908         tcx,
909     ).collect();
910
911     let start_block = BasicBlockData {
912         statements,
913         terminator: Some(Terminator {
914             source_info,
915             kind: TerminatorKind::Return,
916         }),
917         is_cleanup: false
918     };
919
920     let body = new_body(
921         IndexVec::from_elem_n(start_block, 1),
922         IndexVec::from_elem_n(
923             SourceScopeData { span, parent_scope: None }, 1
924         ),
925         local_decls,
926         sig.inputs().len(),
927         span,
928     );
929
930     crate::util::dump_mir(
931         tcx,
932         None,
933         "mir_map",
934         &0,
935         crate::transform::MirSource::item(ctor_id),
936         &body,
937         |_, _| Ok(()),
938     );
939
940     tcx.arena.alloc(body)
941 }