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