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