]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/shim.rs
New upstream version 1.20.0+dfsg1
[rustc.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::middle::const_val::ConstVal;
15 use rustc::mir::*;
16 use rustc::mir::transform::MirSource;
17 use rustc::ty::{self, Ty};
18 use rustc::ty::subst::{Kind, Subst, Substs};
19 use rustc::ty::maps::Providers;
20
21 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
22
23 use syntax::abi::Abi;
24 use syntax::ast;
25 use syntax_pos::Span;
26
27 use std::fmt;
28 use std::iter;
29
30 use transform::{add_call_guards, no_landing_pads, simplify};
31 use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
32 use util::patch::MirPatch;
33
34 pub fn provide(providers: &mut Providers) {
35 providers.mir_shims = make_shim;
36 }
37
38 fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
39 instance: ty::InstanceDef<'tcx>)
40 -> &'tcx Mir<'tcx>
41 {
42 debug!("make_shim({:?})", instance);
43
44 let mut result = match instance {
45 ty::InstanceDef::Item(..) =>
46 bug!("item {:?} passed to make_shim", instance),
47 ty::InstanceDef::FnPtrShim(def_id, ty) => {
48 let trait_ = tcx.trait_of_item(def_id).unwrap();
49 let adjustment = match tcx.lang_items.fn_trait_kind(trait_) {
50 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
51 Some(ty::ClosureKind::FnMut) |
52 Some(ty::ClosureKind::Fn) => Adjustment::Deref,
53 None => bug!("fn pointer {:?} is not an fn", ty)
54 };
55 // HACK: we need the "real" argument types for the MIR,
56 // but because our substs are (Self, Args), where Args
57 // is a tuple, we must include the *concrete* argument
58 // types in the MIR. They will be substituted again with
59 // the param-substs, but because they are concrete, this
60 // will not do any harm.
61 let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
62 let arg_tys = sig.inputs();
63
64 build_call_shim(
65 tcx,
66 def_id,
67 adjustment,
68 CallKind::Indirect,
69 Some(arg_tys)
70 )
71 }
72 ty::InstanceDef::Virtual(def_id, _) => {
73 // We are translating a call back to our def-id, which
74 // trans::mir knows to turn to an actual virtual call.
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.global_tcx()
86 .associated_items(fn_mut)
87 .find(|it| it.kind == ty::AssociatedKind::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::Intrinsic(_) => {
102 bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
103 }
104 };
105 debug!("make_shim({:?}) = untransformed {:?}", instance, result);
106 no_landing_pads::no_landing_pads(tcx, &mut result);
107 simplify::simplify_cfg(&mut result);
108 add_call_guards::add_call_guards(&mut result);
109 debug!("make_shim({:?}) = {:?}", instance, result);
110
111 tcx.alloc_mir(result)
112 }
113
114 #[derive(Copy, Clone, Debug, PartialEq)]
115 enum Adjustment {
116 Identity,
117 Deref,
118 RefMut,
119 }
120
121 #[derive(Copy, Clone, Debug, PartialEq)]
122 enum CallKind {
123 Indirect,
124 Direct(DefId),
125 }
126
127 fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
128 LocalDecl {
129 mutability, ty, name: None,
130 source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span },
131 is_user_variable: false
132 }
133 }
134
135 fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span)
136 -> IndexVec<Local, LocalDecl<'tcx>>
137 {
138 iter::once(temp_decl(Mutability::Mut, sig.output(), span))
139 .chain(sig.inputs().iter().map(
140 |ity| temp_decl(Mutability::Not, ity, span)))
141 .collect()
142 }
143
144 fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
145 def_id: DefId,
146 ty: Option<Ty<'tcx>>)
147 -> Mir<'tcx>
148 {
149 debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
150
151 let substs = if let Some(ty) = ty {
152 tcx.mk_substs(iter::once(Kind::from(ty)))
153 } else {
154 Substs::identity_for_item(tcx, def_id)
155 };
156 let sig = tcx.fn_sig(def_id).subst(tcx, substs);
157 let sig = tcx.erase_late_bound_regions(&sig);
158 let span = tcx.def_span(def_id);
159
160 let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
161
162 let return_block = BasicBlock::new(1);
163 let mut blocks = IndexVec::new();
164 let block = |blocks: &mut IndexVec<_, _>, kind| {
165 blocks.push(BasicBlockData {
166 statements: vec![],
167 terminator: Some(Terminator { source_info, kind }),
168 is_cleanup: false
169 })
170 };
171 block(&mut blocks, TerminatorKind::Goto { target: return_block });
172 block(&mut blocks, TerminatorKind::Return);
173
174 let mut mir = Mir::new(
175 blocks,
176 IndexVec::from_elem_n(
177 VisibilityScopeData { span: span, parent_scope: None }, 1
178 ),
179 IndexVec::new(),
180 sig.output(),
181 local_decls_for_sig(&sig, span),
182 sig.inputs().len(),
183 vec![],
184 span
185 );
186
187 if let Some(..) = ty {
188 let patch = {
189 let param_env = tcx.param_env(def_id);
190 let mut elaborator = DropShimElaborator {
191 mir: &mir,
192 patch: MirPatch::new(&mir),
193 tcx,
194 param_env
195 };
196 let dropee = Lvalue::Local(Local::new(1+0)).deref();
197 let resume_block = elaborator.patch.resume_block();
198 elaborate_drops::elaborate_drop(
199 &mut elaborator,
200 source_info,
201 &dropee,
202 (),
203 return_block,
204 elaborate_drops::Unwind::To(resume_block),
205 START_BLOCK
206 );
207 elaborator.patch
208 };
209 patch.apply(&mut mir);
210 }
211
212 mir
213 }
214
215 pub struct DropShimElaborator<'a, 'tcx: 'a> {
216 mir: &'a Mir<'tcx>,
217 patch: MirPatch<'tcx>,
218 tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
219 param_env: ty::ParamEnv<'tcx>,
220 }
221
222 impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
223 fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
224 Ok(())
225 }
226 }
227
228 impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
229 type Path = ();
230
231 fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch }
232 fn mir(&self) -> &'a Mir<'tcx> { self.mir }
233 fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
234 fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
235
236 fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
237 if let DropFlagMode::Shallow = mode {
238 DropStyle::Static
239 } else {
240 DropStyle::Open
241 }
242 }
243
244 fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
245 None
246 }
247
248 fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {
249 }
250
251 fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
252 None
253 }
254 fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
255 None
256 }
257 fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
258 Some(())
259 }
260 }
261
262 /// Build a "call" shim for `def_id`. The shim calls the
263 /// function specified by `call_kind`, first adjusting its first
264 /// argument according to `rcvr_adjustment`.
265 ///
266 /// If `untuple_args` is a vec of types, the second argument of the
267 /// function will be untupled as these types.
268 fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
269 def_id: DefId,
270 rcvr_adjustment: Adjustment,
271 call_kind: CallKind,
272 untuple_args: Option<&[Ty<'tcx>]>)
273 -> Mir<'tcx>
274 {
275 debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
276 call_kind={:?}, untuple_args={:?})",
277 def_id, rcvr_adjustment, call_kind, untuple_args);
278
279 let sig = tcx.fn_sig(def_id);
280 let sig = tcx.erase_late_bound_regions(&sig);
281 let span = tcx.def_span(def_id);
282
283 debug!("build_call_shim: sig={:?}", sig);
284
285 let mut local_decls = local_decls_for_sig(&sig, span);
286 let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
287
288 let rcvr_arg = Local::new(1+0);
289 let rcvr_l = Lvalue::Local(rcvr_arg);
290 let mut statements = vec![];
291
292 let rcvr = match rcvr_adjustment {
293 Adjustment::Identity => Operand::Consume(rcvr_l),
294 Adjustment::Deref => Operand::Consume(rcvr_l.deref()),
295 Adjustment::RefMut => {
296 // let rcvr = &mut rcvr;
297 let ref_rcvr = local_decls.push(temp_decl(
298 Mutability::Not,
299 tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
300 ty: sig.inputs()[0],
301 mutbl: hir::Mutability::MutMutable
302 }),
303 span
304 ));
305 statements.push(Statement {
306 source_info: source_info,
307 kind: StatementKind::Assign(
308 Lvalue::Local(ref_rcvr),
309 Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
310 )
311 });
312 Operand::Consume(Lvalue::Local(ref_rcvr))
313 }
314 };
315
316 let (callee, mut args) = match call_kind {
317 CallKind::Indirect => (rcvr, vec![]),
318 CallKind::Direct(def_id) => (
319 Operand::Constant(box Constant {
320 span: span,
321 ty: tcx.type_of(def_id),
322 literal: Literal::Value {
323 value: ConstVal::Function(def_id,
324 Substs::identity_for_item(tcx, def_id)),
325 },
326 }),
327 vec![rcvr]
328 )
329 };
330
331 if let Some(untuple_args) = untuple_args {
332 args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
333 let arg_lv = Lvalue::Local(Local::new(1+1));
334 Operand::Consume(arg_lv.field(Field::new(i), *ity))
335 }));
336 } else {
337 args.extend((1..sig.inputs().len()).map(|i| {
338 Operand::Consume(Lvalue::Local(Local::new(1+i)))
339 }));
340 }
341
342 let mut blocks = IndexVec::new();
343 let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
344 blocks.push(BasicBlockData {
345 statements,
346 terminator: Some(Terminator { source_info, kind }),
347 is_cleanup
348 })
349 };
350
351 // BB #0
352 block(&mut blocks, statements, TerminatorKind::Call {
353 func: callee,
354 args: args,
355 destination: Some((Lvalue::Local(RETURN_POINTER),
356 BasicBlock::new(1))),
357 cleanup: if let Adjustment::RefMut = rcvr_adjustment {
358 Some(BasicBlock::new(3))
359 } else {
360 None
361 }
362 }, false);
363
364 if let Adjustment::RefMut = rcvr_adjustment {
365 // BB #1 - drop for Self
366 block(&mut blocks, vec![], TerminatorKind::Drop {
367 location: Lvalue::Local(rcvr_arg),
368 target: BasicBlock::new(2),
369 unwind: None
370 }, false);
371 }
372 // BB #1/#2 - return
373 block(&mut blocks, vec![], TerminatorKind::Return, false);
374 if let Adjustment::RefMut = rcvr_adjustment {
375 // BB #3 - drop if closure panics
376 block(&mut blocks, vec![], TerminatorKind::Drop {
377 location: Lvalue::Local(rcvr_arg),
378 target: BasicBlock::new(4),
379 unwind: None
380 }, true);
381
382 // BB #4 - resume
383 block(&mut blocks, vec![], TerminatorKind::Resume, true);
384 }
385
386 let mut mir = Mir::new(
387 blocks,
388 IndexVec::from_elem_n(
389 VisibilityScopeData { span: span, parent_scope: None }, 1
390 ),
391 IndexVec::new(),
392 sig.output(),
393 local_decls,
394 sig.inputs().len(),
395 vec![],
396 span
397 );
398 if let Abi::RustCall = sig.abi {
399 mir.spread_arg = Some(Local::new(sig.inputs().len()));
400 }
401 mir
402 }
403
404 pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
405 ctor_id: ast::NodeId,
406 fields: &[hir::StructField],
407 span: Span)
408 -> (Mir<'tcx>, MirSource)
409 {
410 let tcx = infcx.tcx;
411 let def_id = tcx.hir.local_def_id(ctor_id);
412 let sig = tcx.no_late_bound_regions(&tcx.fn_sig(def_id))
413 .expect("LBR in ADT constructor signature");
414 let sig = tcx.erase_regions(&sig);
415
416 let (adt_def, substs) = match sig.output().sty {
417 ty::TyAdt(adt_def, substs) => (adt_def, substs),
418 _ => bug!("unexpected type for ADT ctor {:?}", sig.output())
419 };
420
421 debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
422
423 let local_decls = local_decls_for_sig(&sig, span);
424
425 let source_info = SourceInfo {
426 span: span,
427 scope: ARGUMENT_VISIBILITY_SCOPE
428 };
429
430 let variant_no = if adt_def.is_enum() {
431 adt_def.variant_index_with_id(def_id)
432 } else {
433 0
434 };
435
436 // return = ADT(arg0, arg1, ...); return
437 let start_block = BasicBlockData {
438 statements: vec![Statement {
439 source_info: source_info,
440 kind: StatementKind::Assign(
441 Lvalue::Local(RETURN_POINTER),
442 Rvalue::Aggregate(
443 box AggregateKind::Adt(adt_def, variant_no, substs, None),
444 (1..sig.inputs().len()+1).map(|i| {
445 Operand::Consume(Lvalue::Local(Local::new(i)))
446 }).collect()
447 )
448 )
449 }],
450 terminator: Some(Terminator {
451 source_info: source_info,
452 kind: TerminatorKind::Return,
453 }),
454 is_cleanup: false
455 };
456
457 let mir = Mir::new(
458 IndexVec::from_elem_n(start_block, 1),
459 IndexVec::from_elem_n(
460 VisibilityScopeData { span: span, parent_scope: None }, 1
461 ),
462 IndexVec::new(),
463 sig.output(),
464 local_decls,
465 sig.inputs().len(),
466 vec![],
467 span
468 );
469 (mir, MirSource::Fn(ctor_id))
470 }