]>
Commit | Line | Data |
---|---|---|
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 | ||
11 | use rustc::hir; | |
12 | use rustc::hir::def_id::DefId; | |
13 | use rustc::infer; | |
cc61c64b | 14 | use rustc::mir::*; |
94b46f34 XL |
15 | use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind}; |
16 | use rustc::ty::subst::{Subst, Substs}; | |
17 | use rustc::ty::query::Providers; | |
cc61c64b XL |
18 | |
19 | use rustc_data_structures::indexed_vec::{IndexVec, Idx}; | |
20 | ||
83c7162d | 21 | use rustc_target::spec::abi::Abi; |
cc61c64b XL |
22 | use syntax::ast; |
23 | use syntax_pos::Span; | |
24 | ||
cc61c64b XL |
25 | use std::fmt; |
26 | use std::iter; | |
cc61c64b | 27 | |
ff7c6d11 | 28 | use transform::{add_moves_for_packed_drops, add_call_guards}; |
2c00a5a8 | 29 | use transform::{remove_noop_landing_pads, no_landing_pads, simplify}; |
cc61c64b XL |
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 | ||
ea8adc8c | 37 | fn 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)] | |
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 { | |
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 | ||
153 | fn 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 | 162 | fn 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 | ||
240 | pub 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 | ||
247 | impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { | |
248 | fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> { | |
249 | Ok(()) | |
250 | } | |
251 | } | |
252 | ||
253 | impl<'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 | 291 | fn 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 | ||
325 | struct 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 | ||
334 | impl<'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 | 674 | fn 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 | ||
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) | |
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 | } |